package com.iwhalecloud.bss.kite.cucc.service.scene;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.iwhalecloud.bss.kite.client.api.scene.operate.IOperateSceneAdditionalOfferInstService;
import com.iwhalecloud.bss.kite.client.api.scene.operate.IOperateSceneFuncProdInstService;
import com.iwhalecloud.bss.kite.client.api.scene.operate.IOperateSceneOfferInstService;
import com.iwhalecloud.bss.kite.client.api.scene.operate.IOperateSceneProdInstService;
import com.iwhalecloud.bss.kite.client.api.scene.query.IQuerySceneCommonService;
import com.iwhalecloud.bss.kite.client.api.scene.query.IQuerySceneMainOfferInstService;
import com.iwhalecloud.bss.kite.client.dto.DataResult;
import com.iwhalecloud.bss.kite.client.dto.inst.OfferInstDTO;
import com.iwhalecloud.bss.kite.client.dto.inst.ProdInstDTO;
import com.iwhalecloud.bss.kite.client.enums.TriggerStrategy;
import com.iwhalecloud.bss.kite.client.vo.scene.ProdAttrModuleVO;
import com.iwhalecloud.bss.kite.client.vo.scene.ProdAttrVO;
import com.iwhalecloud.bss.kite.client.vo.scene.ProdFuncVO;
import com.iwhalecloud.bss.kite.common.constant.ErrorConsts;
import com.iwhalecloud.bss.kite.common.constant.KeyConsts;
import com.iwhalecloud.bss.kite.common.constant.ServiceOfferConsts;
import com.iwhalecloud.bss.kite.common.constant.SymbolConsts;
import com.iwhalecloud.bss.kite.common.util.FunctionWrapper;
import com.iwhalecloud.bss.kite.common.util.KiteBeanUtils;
import com.iwhalecloud.bss.kite.common.util.KiteDateUtils;
import com.iwhalecloud.bss.kite.common.util.KiteListUtils;
import com.iwhalecloud.bss.kite.common.util.KiteMapUtils;
import com.iwhalecloud.bss.kite.common.util.KiteObjectUtils;
import com.iwhalecloud.bss.kite.common.util.KiteStringUtils;
import com.iwhalecloud.bss.kite.common.util.SeqUtils;
import com.iwhalecloud.bss.kite.cucc.client.api.account.ILocalAccountService;
import com.iwhalecloud.bss.kite.cucc.client.api.scene.IInitSceneOfferInstService;
import com.iwhalecloud.bss.kite.cucc.client.dto.account.QryCustAccountReq;
import com.iwhalecloud.bss.kite.cucc.client.dto.attr.ChargeUnitDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.attr.ChargeUnitQryDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosAccountDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosAttachmentDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosAttrDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosContractDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosDeliveryDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosDiscountDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosGoodsDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosGoodsFeeDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosGoodsPayRealtionDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosProductDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosUserDTO;
import com.iwhalecloud.bss.kite.cucc.client.service.cache.ILocalRefreshCacheService;
import com.iwhalecloud.bss.kite.cucc.common.constant.LocalKeyConsts;
import com.iwhalecloud.bss.kite.cucc.common.constant.LocalServiceOfferConsts;
import com.iwhalecloud.bss.kite.cucc.common.util.CommonUtil;
import com.iwhalecloud.bss.kite.cucc.common.util.DateFormatUtils;
import com.iwhalecloud.bss.kite.cucc.common.util.DateUtils;
import com.iwhalecloud.bss.kite.cucc.common.util.StrTools;
import com.iwhalecloud.bss.kite.cucc.manager.inst.CuccKiteOfferInstAcct;
import com.iwhalecloud.bss.kite.cucc.service.attr.LocalAttrHelper;
import com.iwhalecloud.bss.kite.cucc.service.batch.LocalBatchAcceptBO;
import com.iwhalecloud.bss.kite.cucc.service.cache.ChargeUnitCache;
import com.iwhalecloud.bss.kite.cucc.service.goods.GoodsHelper;
import com.iwhalecloud.bss.kite.cucc.service.pos.handler.CuccPosServiceUtils;
import com.iwhalecloud.bss.kite.cucc.service.scene.attr.CuccOperateInstAttrService;
import com.iwhalecloud.bss.kite.cucc.service.util.ChangeTypeUtils;
import com.iwhalecloud.bss.kite.cucc.service.util.ProdCateUtil;
import com.iwhalecloud.bss.kite.cucc.spec.impl.transfer.GoodsInfoTransfer;
import com.iwhalecloud.bss.kite.dataservice.cache.AttrValueCache;
import com.iwhalecloud.bss.kite.dataservice.cache.DcPublicCache;
import com.iwhalecloud.bss.kite.dataservice.cache.OfferAttrCache;
import com.iwhalecloud.bss.kite.dataservice.cache.OfferCache;
import com.iwhalecloud.bss.kite.dataservice.cache.ProdFeeAttrCache;
import com.iwhalecloud.bss.kite.dataservice.cache.ProdFeeCache;
import com.iwhalecloud.bss.kite.dataservice.cache.ProdHisAttrCache;
import com.iwhalecloud.bss.kite.dataservice.cache.ProdRelCache;
import com.iwhalecloud.bss.kite.dataservice.cache.ProductCache;
import com.iwhalecloud.bss.kite.dataservice.entity.AttrValue;
import com.iwhalecloud.bss.kite.dataservice.entity.DcPublic;
import com.iwhalecloud.bss.kite.dataservice.entity.OfferAttr;
import com.iwhalecloud.bss.kite.dataservice.entity.spec.Offer;
import com.iwhalecloud.bss.kite.dataservice.entity.spec.ProdRelInfo;
import com.iwhalecloud.bss.kite.dataservice.entity.spec.Product;
import com.iwhalecloud.bss.kite.dataservice.util.GeneralSwitchUtils;
import com.iwhalecloud.bss.kite.dataservice.util.IdUtils;
import com.iwhalecloud.bss.kite.manager.api.IOperateSceneInstService;
import com.iwhalecloud.bss.kite.manager.api.IQuerySceneInstService;
import com.iwhalecloud.bss.kite.manager.dto.ContAttachmentDTO;
import com.iwhalecloud.bss.kite.manager.dto.KiteInstRelDTO;
import com.iwhalecloud.bss.kite.manager.enums.ActionType;
import com.iwhalecloud.bss.kite.manager.enums.InstType;
import com.iwhalecloud.bss.kite.manager.enums.RelType;
import com.iwhalecloud.bss.kite.manager.inst.KiteAttr;
import com.iwhalecloud.bss.kite.manager.inst.KiteAttrValue;
import com.iwhalecloud.bss.kite.manager.inst.KiteInst;
import com.iwhalecloud.bss.kite.manager.inst.KiteOfferInst;
import com.iwhalecloud.bss.kite.manager.inst.KiteOfferInstContract;
import com.iwhalecloud.bss.kite.manager.inst.KiteOfferInstDiscount;
import com.iwhalecloud.bss.kite.manager.inst.KiteProdInst;
import com.iwhalecloud.bss.kite.manager.inst.KiteProdInstFunc;
import com.iwhalecloud.bss.kite.manager.inst.KiteSceneInst;
import com.iwhalecloud.bss.kite.manager.scene.service.operate.OperateChangeService;
import com.iwhalecloud.bss.kite.manager.transaction.KiteTransactional;
import com.iwhalecloud.bss.kite.manager.util.KiteTransactionUtils;
import com.iwhalecloud.bss.kite.service.scene.attr.OperateInstAttrService;
import com.ztesoft.bss.common.bo.LoginInfo;
import com.ztesoft.bss.common.util.ContextUtil;
import com.ztesoft.bss.common.util.DateUtil;
import com.ztesoft.bss.common.util.SpringUtil;
import com.ztesoft.bss.common.util.StringUtil;
import com.ztesoft.common.logger.api.ZLogger;
import com.ztesoft.common.logger.factory.ZLoggerFactory;

import edu.emory.mathcs.backport.java.util.Collections;

@Service
public class InitSceneOfferInstService implements IInitSceneOfferInstService {

    private static final ZLogger LOGGER = ZLoggerFactory.getLogger(InitSceneOfferInstService.class, KeyConsts.LOG_MODULE);

    @Autowired
    private IQuerySceneInstService querySceneInstService;

    @Autowired
    private IOperateSceneInstService operateSceneInstService;

    @Autowired
    private IOperateSceneOfferInstService operateSceneOfferInstService;

    @Autowired
    private IOperateSceneFuncProdInstService operateSceneFuncProdInstService;

    @Autowired
    private IOperateSceneProdInstService operateSceneProdInstService;

    @Autowired
    private OperateInstAttrService operateInstAttrService;

    @Autowired
    private IOperateSceneAdditionalOfferInstService operateSceneAdditionalOfferInstService;

    @Autowired
    private IQuerySceneMainOfferInstService querySceneMainOfferInstService;

    @Autowired
    private IQuerySceneCommonService querySceneCommonService;

    @Resource(name = "manager.operateChangeService")
    private OperateChangeService operateChangeService;

    @Autowired
    private IQuerySceneInstService sceneInstQueryService;

    @Autowired
    private ILocalAccountService localAccountService;

    @Override
    @KiteTransactional
    public void initGiftOfferInst(String sceneInstId, String custId, String staffId, List<KitePosGoodsDTO> posGoods, LoginInfo loginInfo) {
        if (KiteListUtils.isEmpty(posGoods)) {
            return;
        }
        posGoods = posGoods.stream()
            .filter(offerInst -> !GoodsInfoTransfer.isAddRoleOffer(offerInst.getCode(), offerInst.getCatagoryId()) && GoodsHelper.isGift(offerInst.getCode()))
            .collect(Collectors.toList());
        if (KiteListUtils.isEmpty(posGoods)) {
            return;
        }
        KitePosProductDTO kitePosProductDTO = null;
        Map<String, String> serialNumberMap = querySceneInstService.getExtParameterValue(sceneInstId, "serialNumberMap");
        String goodInstanceId = "";
        for (KitePosGoodsDTO goods : posGoods) {
            List<KiteOfferInst> offerInsts = this.querySceneInstService.listGiftOfferInsts(sceneInstId);
            if (KiteListUtils.isNotEmpty(offerInsts)) {
                KiteOfferInst offerInst = offerInsts.get(0);
                List<KitePosProductDTO> products = goods.getProducts();
                if (KiteListUtils.isNotEmpty(products)) {
                    kitePosProductDTO = products.get(0);
                    goodInstanceId = goods.getInstanceId();
                }
                CuccPosServiceUtils.setExtParamValue(offerInst, sceneInstId, "saleGoodsCode", goods.getSaleGoodsCode());
                CuccPosServiceUtils.setExtParamValue(offerInst, sceneInstId, "saleGoodsName", goods.getSaleGoodsName());
                this.setExtOfferInstId(sceneInstId, goods.getDestItemId(), custId, offerInst);
            }
        }
        String rootInstId = querySceneInstService.getSceneInst(sceneInstId).getRootInstId();
        KiteOfferInst offerInst = querySceneInstService.getOfferInst(custId, rootInstId);
        if (KiteObjectUtils.isEmpty(offerInst)) {
            return;
        }
        List<KiteProdInst> prodInsts = querySceneInstService.listProdInstsFromOfferInst(custId, offerInst.getOfferInstId());
        if (KiteListUtils.isNotEmpty(prodInsts) && Objects.nonNull(kitePosProductDTO)) {
            List<KitePosAttrDTO> attrs = kitePosProductDTO.getAttrs();
            // 融合业务号码处理
            String serialNumber = KiteMapUtils.getString(serialNumberMap, goodInstanceId);
            if (KiteStringUtils.isNotEmpty(serialNumber)) {
                Map<String, String> instSerialNumberMap = querySceneInstService.getExtParameterValue(sceneInstId, "instSerialNumberMap");
                if (Objects.nonNull(instSerialNumberMap)) {
                    instSerialNumberMap.put(prodInsts.get(0).getProdInstId(), serialNumber);
                }
            }
            this.setProdInstAttrValue(sceneInstId, kitePosProductDTO.getDestItemId(), prodInsts.get(0),null,
                attrs, loginInfo);
        }
    }

    @Override
    @KiteTransactional
    public void initMainOfferInst(String sceneInstId, String custId, String staffId, List<KitePosGoodsDTO> posGoods, LoginInfo loginInfo) {
        if (KiteListUtils.isEmpty(posGoods)) {
            return;
        }
        boolean parentIsGift = posGoods.stream().anyMatch(kitePosGoodsDTO -> GoodsHelper.isGift(kitePosGoodsDTO.getCode()));
        posGoods = posGoods.stream()
            .filter(offerInst -> !GoodsInfoTransfer.isAddRoleOffer(offerInst.getCode(), offerInst.getCatagoryId()) && !GoodsHelper.isGift(offerInst.getCode()))
            .collect(Collectors.toList());
        if (KiteListUtils.isEmpty(posGoods)) {
            return;
        }
        //FIXME 批量受理签订起租还原场景临时处理
        if (KiteStringUtils.equalsAny(querySceneInstService.getExtParameterValue(sceneInstId, "preTaskCode"),
            "batchSIGN", "batchOrderStartRent")) {
            posGoods = Lists.newArrayList(posGoods.get(0));
        }
        for (KitePosGoodsDTO goods : posGoods) {
            String offerId = goods.getCode();
            List<KiteOfferInst> offerInsts = this.querySceneInstService.listMainOfferInsts(sceneInstId, offerId);
            if (KiteListUtils.isEmpty(offerInsts)) {
                this.operateSceneOfferInstService.addOfferInst(sceneInstId, offerId, custId, staffId);
                offerInsts = this.querySceneInstService.listMainOfferInsts(sceneInstId, offerId);
            }
            if (KiteListUtils.isNotEmpty(offerInsts)) {
                for (KiteOfferInst offerInst : offerInsts) {
                    String offerInstId = offerInst.getOfferInstId();
                    this.setExtOfferInstId(sceneInstId, goods, custId, offerInst);
                    this.dealProducts(sceneInstId, custId, staffId, offerId, offerInstId, goods, parentIsGift, loginInfo);
                }
            }
        }
    }

    private void dealProducts(String sceneInstId, String custId, String staffId, String offerId, String offerInstId, KitePosGoodsDTO goods, boolean parentIsGift, LoginInfo loginInfo) {
        List<KitePosProductDTO> products = goods.getProducts();
        if (KiteListUtils.isEmpty(products)) {
            return;
        }
        List<String> existsInstanceId = Lists.newArrayList();
        Map<String, String> serialNumberMap = querySceneInstService.getExtParameterValue(sceneInstId, "serialNumberMap");
        List<KiteProdInst> prodInsts = sceneInstQueryService.listProdInstsFromOfferInst(custId, offerInstId);
        for (KiteProdInst accessProdInst : prodInsts) {
            KitePosProductDTO product = products.stream().filter(prod -> KiteStringUtils.equals(prod.getCode(), accessProdInst.getSpecId())).findFirst().orElse(null);
            if (KiteObjectUtils.isEmpty(product) || existsInstanceId.contains(product.getInstanceId())) {
                continue;
            }
            existsInstanceId.add(product.getInstanceId());
            String prodInstId = accessProdInst.getProdInstId();
            List<KitePosAttrDTO> attrs = product.getAttrs().stream().filter(attr -> !LocalKeyConsts.ATTR_TYPE_GROUP.equals(attr.getType())).collect(Collectors.toList());
            // 融合业务号码处理 && 解决融合子单起租失败重提时,成员商品匹配userInstId为空问题。
            String serialNumber = KiteMapUtils.getString(serialNumberMap, goods.getInstanceId());
            if (KiteStringUtils.isNotEmpty(serialNumber)) {
                Map<String, String> instSerialNumberMap = querySceneInstService
                    .getExtParameterValue(sceneInstId, "instSerialNumberMap");
                if (Objects.nonNull(instSerialNumberMap)) {
                    instSerialNumberMap.put(accessProdInst.getProdInstId(), serialNumber);
                }
            }

            /** 属性组类的属性处理  begin **/
            List<KitePosAttrDTO> attrGroups = product.getAttrs().stream().filter(attr -> LocalKeyConsts.ATTR_TYPE_GROUP.equals(attr.getType())).collect(Collectors.toList());
            Map<String, KitePosAttrDTO> attrGroupMap = attrGroups.stream()
                .collect(Collectors.toMap(KitePosAttrDTO::getCode, kitePosAttrDTO -> kitePosAttrDTO, (a, b) -> b));
            // 后面转单组装属性组时用到
            if (KiteMapUtils.isNotEmpty(attrGroupMap)) {
                operateSceneInstService.putExtParameter(sceneInstId, "attrGroupMap_".concat(prodInstId), attrGroupMap);
            }
            List<KiteAttr> connectButtonTypeAttrs = accessProdInst.listAttrs().stream().filter(attr -> KiteStringUtils.equals(KeyConsts.GEN_LOGIC, attr.getAttrValueTypeId())).collect(Collectors.toList());
            // APN、通信计划、5G切片、附加产品
            List<KiteAttr> prodFuncIdAttrs = connectButtonTypeAttrs.stream().filter(idAttr -> KiteStringUtils.equals(ProductCache.get(idAttr.getGroupId()).getProdFuncType(), KeyConsts.PROD_FUNC_TYPE_102)).collect(Collectors.toList());
            this.initProdInstFunc(sceneInstId, custId, staffId, prodInstId, attrGroups, prodFuncIdAttrs, loginInfo);
            // 资费计划
            List<KiteAttr> prodIdAttrs = connectButtonTypeAttrs.stream().filter(idAttr -> KiteStringUtils.equals(ProductCache.get(idAttr.getGroupId()).getProdFuncType(), KeyConsts.PROD_FUNC_TYPE_101)).collect(Collectors.toList());
            this.initTariffPlanProdInst(sceneInstId, offerInstId, custId, staffId, product, prodIdAttrs, loginInfo, accessProdInst);
            // 承诺
            List<KiteAttr> connectTypeOtherAttrs = accessProdInst.listAttrs().stream().filter(attr -> !KiteStringUtils.equals(KeyConsts.GEN_LOGIC, attr.getAttrValueTypeId())).collect(Collectors.toList());
            this.initProdOtherAttrs(sceneInstId, custId, prodInstId, attrGroups, connectTypeOtherAttrs, loginInfo);
            // 互联网大带宽 附件属性还原
            List<KiteAttr> attachmentsAttrs = accessProdInst.listAttrs().stream().filter(attr -> KiteStringUtils.equals(attr.getFieldName(), "300000203")).collect(Collectors.toList());
            this.initAttachmentProdInstInfo(sceneInstId, custId, staffId, prodInstId, attrGroups, attachmentsAttrs, loginInfo, accessProdInst);
            this.initAttachmentFromAttrGrp(accessProdInst,attrGroups,offerId,sceneInstId);
            /** 属性组类的属性处理  end **/
            /** 接入产品的非属性组类属性处理  begin **/
            this.setProdInstAttrValue(sceneInstId, product.getDestItemId(), accessProdInst, accessProdInst, attrs, loginInfo);
            // 处理一对多场景属性还原
            dealProdSpecAttr(sceneInstId, accessProdInst, attrs, loginInfo);
            dealProdInstAttrsforBussChange(sceneInstId, accessProdInst, custId);
            /** 接入产品的非属性组类属性处理  end **/

            // 属性还原完毕后特殊处理
            this.afterProdAttrExecute(sceneInstId, custId);

            // 还原产品实例动作
            String changeType = dealFunProdInstActionType(attrs);
            if (KiteStringUtils.isEqual(product.getChangeType(), ChangeTypeUtils.CHANGE_TYPE_A)) {
                changeType = ChangeTypeUtils.CHANGE_TYPE_A;
            }

            if (KiteStringUtils.isNotEmpty(changeType)) {
                if (KiteStringUtils.equals(ChangeTypeUtils.CHANGE_TYPE_D, changeType)) {
                    operateSceneProdInstService.deleteProdInstForOffer(sceneInstId, offerInstId, prodInstId, custId);
                }
                else {
                    if(KiteStringUtils.isEqual(changeType, ChangeTypeUtils.CHANGE_TYPE_A)) {
                        // 追单，记录初始化的 instId，用于校验追单是否有业务信息变更校验（changeType都是A，无法判断是否是新增）
                        KiteSceneInst sceneInst = this.querySceneInstService.getSceneInst(sceneInstId);
                        String bizType = querySceneInstService.getExtParameterValue(sceneInstId, "bizType");
                        if(KiteStringUtils.isEqual(sceneInst.getServiceOfferId(), LocalServiceOfferConsts.SERVICE_OFFER_FOLLOW) && "1001".equals(bizType)) {
                            String prodFollowInstIds = querySceneInstService.getExtParameterValue(sceneInstId, "prodFollowInstIds");
                            prodFollowInstIds = KiteStringUtils.isEmpty(prodFollowInstIds) ? accessProdInst.getInstId() : (prodFollowInstIds + SymbolConsts.COMMA + accessProdInst.getInstId());

                            operateSceneInstService.putExtParameter(sceneInstId, "offerFollowInstIds", prodFollowInstIds);
                        }
                    }

                    accessProdInst.setActionType(ChangeTypeUtils.getActionType(changeType));
                    operateSceneInstService.addProdInst(sceneInstId, accessProdInst);
                }
            }
        }
    }

    /**
     * 初始化资费计划
     *
     * @param sceneInstId
     * @param offerInstId
     * @param custId
     * @param staffId
     * @param product
     */
    private void initTariffPlanProdInst(String sceneInstId, String offerInstId, String custId, String staffId, KitePosProductDTO product, List<KiteAttr> prodIdAttrs, LoginInfo loginInfo, KiteProdInst accessProdInst) {
        // 找到资费计划基本信息属性组，有多少个基本信息属性组就初始化多少个资费计划产品
        //List<Product> funcProds = Lists.newArrayList();
        // 加装的产品-资费计划
        //List<Product> zProducts = ProdRelCache.getByA(product.getCode(), RelType.PROD_REL_TYPE_100398.getCode());
        if (!KiteListUtils.isEmpty(prodIdAttrs)) {
            Map<String, Object> servInfoMap = new HashMap<>();
            List<Map<String, Object>> servInfos = Lists.newArrayList();
            List<KitePosAttrDTO> baseAttrGroups = product.getAttrs().stream().filter(attr ->
                ("300000170".equals(attr.getCode()) || "30000017011".equals(attr.getCode()) || "30000017012"
                    .equals(attr.getCode()) || LocalKeyConsts.FUNC_PROD_ID_YF5GZF_BASE.equals(attr.getCode())) && LocalKeyConsts.ATTR_TYPE_GROUP.equals(attr.getType())).collect(Collectors.toList());
            List<KitePosAttrDTO> servAttrGroups = product.getAttrs().stream().filter(attr ->
                ("300000171".equals(attr.getCode()) || "30000017111".equals(attr.getCode()) || "30000017112"
                    .equals(attr.getCode()) || LocalKeyConsts.FUNC_PROD_ID_YF5GZF_FW.equals(attr.getCode())) && LocalKeyConsts.ATTR_TYPE_GROUP.equals(attr.getType())).collect(Collectors.toList());
            List<KitePosAttrDTO> disctAttrGroups = product.getAttrs().stream().filter(attr ->
                ("300000172".equals(attr.getCode()) || "30000017211".equals(attr.getCode()) || "30000017212"
                    .equals(attr.getCode()) || LocalKeyConsts.FUNC_PROD_ID_YF5GZF_ZK.equals(attr.getCode())) && LocalKeyConsts.ATTR_TYPE_GROUP.equals(attr.getType())).collect(Collectors.toList());
            //通用连接资费计划
            if (KiteListUtils.isEmpty(baseAttrGroups)) {
                baseAttrGroups = product.getAttrs().stream().filter(attr ->
                    ("300000152".equals(attr.getCode())) && LocalKeyConsts.ATTR_TYPE_GROUP.equals(attr.getType())).collect(Collectors.toList());
            }
            for (KitePosAttrDTO attrGroup : baseAttrGroups) {
                /**
                 * 目前属性组的形式是同一个组只有一个节点,value的如果是长度为1的json数组,意味着只有一个实例
                 * 如果长度大于1,那么就是多个资费计划,所以用while循环遍历这个数组,每一次都创建一个接入产品,通过资费计划标识属性找出功能产品挂上去
                 */
                Map<String, Object> attrValueMap = JSONObject.parseObject(attrGroup.getValue(), Map.class);
                Iterator<String> it = attrValueMap.keySet().iterator();
                while (it.hasNext()) {
                    for (KiteAttr prodIdAttr : prodIdAttrs) {
                        //资费产品实例化
                        ProdInstDTO prodInstDto = operateSceneProdInstService.addProdRole(sceneInstId, staffId, custId, offerInstId, prodIdAttr.getGroupId(), KeyConsts.IPTV_ADD_ROLE, null, null, null);
                        List<KiteProdInstFunc> prodInstFuncs = this.querySceneInstService.listProdInstFuncsBySceneInstId(prodInstDto.getProdInstId(), sceneInstId);
                        List<KiteProdInstFunc> baseProdInstFuncs = prodInstFuncs.stream().filter(prodInstFunc -> KiteStringUtils.equalsAny(ProductCache.get(prodInstFunc.getSpecId()).getProdNbr(), "300000170", LocalKeyConsts.FUNC_PROD_ID_YF5GZF_BASE)).collect(Collectors.toList());
                        List<KiteProdInstFunc> servProdInstFuncs = prodInstFuncs.stream().filter(prodInstFunc -> KiteStringUtils.equalsAny(ProductCache.get(prodInstFunc.getSpecId()).getProdNbr(), "300000171", LocalKeyConsts.FUNC_PROD_ID_YF5GZF_FW)).collect(Collectors.toList());
                        List<KiteProdInstFunc> disctProdInstFuncs = prodInstFuncs.stream().filter(prodInstFunc -> KiteStringUtils.equalsAny(ProductCache.get(prodInstFunc.getSpecId()).getProdNbr(), "300000172", LocalKeyConsts.FUNC_PROD_ID_YF5GZF_ZK)).collect(Collectors.toList());

                        //资费计划基本信息-资费计划标识属性200004129
                        //资费计划服务信息-资费计划标识属性200004145
                        //资费计划折扣信息-资费计划标识属性200004146
                        String attrGroupInstId = it.next();
                        JSONArray attrListValue = (JSONArray) attrValueMap.get(attrGroupInstId);
                        List<KitePosAttrDTO> prodInstAttrs = JSONArray.parseArray(JSONArray.toJSONString(attrListValue), KitePosAttrDTO.class);

                        String feePlanInstId = null;
                        List<KitePosAttrDTO> idAttrs = prodInstAttrs.stream().filter(attr -> KiteStringUtils.equals("200004129", attr.getCode())).collect(Collectors.toList()); //资费计划标识
                        if (!KiteListUtils.isEmpty(idAttrs)) {
                            feePlanInstId = idAttrs.get(0).getValue();
                        }
                        Map<String, List<KitePosAttrDTO>> servAttrGroupMap = this.getSameFeePlanAttrGroups("200004145", feePlanInstId, servAttrGroups);
                        Map<String, List<KitePosAttrDTO>> disctAttrGroupMap = this.getSameFeePlanAttrGroups("200004146", feePlanInstId, disctAttrGroups);

                        // 实例化产品时已经实例化了功能产品，直接设置属性
                        if (KiteListUtils.isNotEmpty(baseProdInstFuncs)) {
                            KiteProdInstFunc prodInstFunc = baseProdInstFuncs.get(0);
                            this.setProdInstAttrValue(sceneInstId, null, prodInstFunc, accessProdInst, prodInstAttrs, loginInfo);
                            // 删除平台服务级别、平台功能费(%)两个属性之外，再进行实例动作还原
                            prodInstAttrs.removeIf(attr -> KiteStringUtils.equalsAny(attr.getCode(), "200003681","200004024"));

                            boolean isDeleteChangeType = false;
                            String changeType = dealFunProdInstActionType(prodInstAttrs);
                            if (KiteStringUtils.isNotEmpty(changeType)) {
                                // 还原他的动作
                                if (KiteStringUtils.equals(ChangeTypeUtils.CHANGE_TYPE_D, changeType)) {
                                    isDeleteChangeType = true;
                                    operateSceneFuncProdInstService.removeFuncProdInst(sceneInstId, prodInstDto.getProdInstId(), prodInstFunc.getProdInstId(), custId, staffId);
                                }
                                else {
                                    prodInstFunc.setActionType(ChangeTypeUtils.getActionType(changeType));
                                }
                            }
                            if (!isDeleteChangeType) {
                                // 设置对端的属性组实例ID
                                prodInstFunc.setExtProdInstId(attrGroupInstId);
                                //prodInstFunc.setExtParamValue(LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + prodInstFunc.getSpecId(), attrGroupInstId);
                                CuccPosServiceUtils.setExtParamValue(prodInstFunc, sceneInstId, LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + prodInstFunc.getSpecId(), attrGroupInstId);
                                operateSceneInstService.addProdInstFunc(sceneInstId, prodInstFunc);
                            }
                        }
                        //资费计划服务信息
                        if (KiteListUtils.isNotEmpty(servProdInstFuncs) && KiteMapUtils.isNotEmpty(servAttrGroupMap)) {
                            KiteProdInstFunc prodInstFunc = servProdInstFuncs.get(0);
                            Map<String, Object> servAttrGroup = getOneAndRemove(servAttrGroupMap);
                            String attrGroupInstIdd = (String) servAttrGroup.get("key");
                            List<KitePosAttrDTO> prodInstFcunAttrs = (List<KitePosAttrDTO>) servAttrGroup.get("value");
                            this.setProdInstAttrValue(sceneInstId, null, prodInstFunc,accessProdInst, prodInstFcunAttrs, loginInfo);
                            // 删除平台服务级别、平台功能费(%)两个属性之外，再进行实例动作还原
                            prodInstFcunAttrs.removeIf(attr -> KiteStringUtils.equalsAny(attr.getCode(), "200003681", "200004024"));

                            boolean isDeleteChangeType = false;
                            String changeType = dealFunProdInstActionType(prodInstFcunAttrs);
                            if (KiteStringUtils.isNotEmpty(changeType)) {
                                // 还原他的动作
                                if (KiteStringUtils.equals(ChangeTypeUtils.CHANGE_TYPE_D, changeType)) {
                                    isDeleteChangeType = true;
                                    operateSceneFuncProdInstService.removeFuncProdInst(sceneInstId, prodInstDto.getProdInstId(), prodInstFunc.getProdInstId(), custId, staffId);
                                }
                                else {
                                    prodInstFunc.setActionType(ChangeTypeUtils.getActionType(changeType));
                                }
                            }
                            if (!isDeleteChangeType) {
                                // 设置对端的属性组实例ID
                                prodInstFunc.setExtProdInstId(attrGroupInstIdd);
                                //prodInstFunc.setExtParamValue(LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + prodInstFunc.getSpecId(), _attrGroupInstId);
                                CuccPosServiceUtils.setExtParamValue(prodInstFunc, sceneInstId, LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + prodInstFunc.getSpecId(), attrGroupInstIdd);
                                operateSceneInstService.addProdInstFunc(sceneInstId, prodInstFunc);
                            }
                        }
                        // 资费计划服务信息可以添加多个，在这里处理
                        if (KiteMapUtils.isNotEmpty(servAttrGroupMap)) {
                            servInfoMap.put("servAttrGroupMap", servAttrGroupMap);
                            servInfoMap.put("parentInstId", prodInstDto.getProdInstId());
                            servInfoMap.put("specId", servProdInstFuncs.get(0).getProdId());
                            asyncservInfos(custId, sceneInstId, servAttrGroupMap, prodInstDto.getProdInstId(), servProdInstFuncs.get(0).getProdId(), loginInfo, accessProdInst, staffId);
                            servInfos.add(servInfoMap);
                            // 启动异步线程还原资费计划服务信息，设置标识，标识为T时不能到订单预览，不能提交订单
                            operateSceneInstService.putExtParameter(sceneInstId, "loadingTariffPlanFlag", "T");
                        }
                        // 资费计划折扣信息
                        if (KiteListUtils.isNotEmpty(disctProdInstFuncs) && KiteMapUtils.isNotEmpty(disctAttrGroupMap)) {
                            KiteProdInstFunc prodInstFunc = disctProdInstFuncs.get(0);
                            Map<String, Object> disctAttrGroup = getOneAndRemove(disctAttrGroupMap);
                            String attrGroupInstIdd = (String) disctAttrGroup.get("key");
                            List<KitePosAttrDTO> prodInstFcunAttrs = (List<KitePosAttrDTO>) disctAttrGroup.get("value");
                            this.setProdInstAttrValue(sceneInstId, null, disctProdInstFuncs.get(0), accessProdInst, prodInstFcunAttrs, loginInfo);
                            // 记录原始折扣率
                            String discountRateValue = prodInstFcunAttrs.stream().filter(attr -> "200001694".equals(attr.getCode()))
                                .findFirst().map(KitePosAttrDTO::getValue).orElse("");
                            CuccPosServiceUtils.setExtParamValue(prodInstFunc, sceneInstId, "discountRateOriginalValue", discountRateValue);
                            // 删除平台服务级别、平台功能费(%)两个属性之外，再进行实例动作还原
                            prodInstFcunAttrs.removeIf(attr -> KiteStringUtils.equalsAny(attr.getCode(), "200003681", "200004024"));

                            boolean isDeleteChangeType = false;
                            String changeType = dealFunProdInstActionType(prodInstFcunAttrs);
                            if (KiteStringUtils.isNotEmpty(changeType)) {
                                // 还原他的动作
                                if (KiteStringUtils.equals(ChangeTypeUtils.CHANGE_TYPE_D, changeType)) {
                                    isDeleteChangeType = true;
                                    operateSceneFuncProdInstService.removeFuncProdInst(sceneInstId, prodInstDto.getProdInstId(), prodInstFunc.getProdInstId(), custId, staffId);
                                }
                                else {
                                    prodInstFunc.setActionType(ChangeTypeUtils.getActionType(changeType));
                                }
                            }
                            if (!isDeleteChangeType) {
                                // 设置对端的属性组实例ID
                                prodInstFunc.setExtProdInstId(attrGroupInstIdd);
                                //prodInstFunc.setExtParamValue(LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + prodInstFunc.getSpecId(), _attrGroupInstId);
                                CuccPosServiceUtils.setExtParamValue(prodInstFunc, sceneInstId, LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + prodInstFunc.getSpecId(), attrGroupInstIdd);
                                operateSceneInstService.addProdInstFunc(sceneInstId, prodInstFunc);
                            }
                        }
                    }
                }
            }
//            if (!KiteListUtils.isEmpty(servInfos)) {
//                CompletableFuture.runAsync(
//                    FunctionWrapper.wrapLoginInfoAndTrans(() -> {
//                        try {
//                            for (Map<String, Object> servInfo : servInfos) {
//                                Map<String, List<KitePosAttrDTO>> servAttrGroupMap = (Map<String, List<KitePosAttrDTO>>) servInfo.get("servAttrGroupMap");
//                                String parentInstId = (String) servInfo.get("parentInstId");
//                                String specId = (String) servInfo.get("specId");
//                                while (KiteMapUtils.isNotEmpty(servAttrGroupMap)) {
//                                    Map<String, Object> servAttrGroup = getOneAndRemove(servAttrGroupMap);
//                                    String attrGroupInstIdStr = (String) servAttrGroup.get("key");
//                                    List<KitePosAttrDTO> prodInstFcunAttrs = (List<KitePosAttrDTO>) servAttrGroup.get("value");
//                                    DataResult<ProdFuncVO> result = operateSceneFuncProdInstService.addFuncProdInstWithoutRuleTrigger(sceneInstId, parentInstId, specId, custId, staffId);
//                                    KiteProdInstFunc prodInstFunc = this.querySceneInstService.getProdInstFunc(custId, result.getResultObject().getProdInstId());
//                                    this.setProdInstAttrValue(sceneInstId, null, prodInstFunc, accessProdInst, prodInstFcunAttrs, loginInfo);
//                                    prodInstFcunAttrs.removeIf(attr -> KiteStringUtils.equalsAny(attr.getCode(), "200003681","200004024"));
//                                    boolean isDeleteChangeType = false;
//                                    String changeType = dealFunProdInstActionType(prodInstFcunAttrs);
//                                    if (KiteStringUtils.isNotEmpty(changeType)) {
//                                        // 还原他的动作
//                                        if (KiteStringUtils.equals(ChangeTypeUtils.CHANGE_TYPE_D, changeType)) {
//                                            isDeleteChangeType = true;
//                                            operateSceneFuncProdInstService.removeFuncProdInst(sceneInstId, parentInstId, prodInstFunc.getProdInstId(), custId, staffId);
//                                        }
//                                        else {
//                                            prodInstFunc.setActionType(ChangeTypeUtils.getActionType(changeType));
//                                        }
//                                    }
//                                    if (!isDeleteChangeType) {
//                                        // 设置对端的属性组实例ID
//                                        prodInstFunc.setExtProdInstId(attrGroupInstIdStr);
//                                        //prodInstFunc.setExtParamValue(LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + prodInstFunc.getSpecId(), attrGroupInstIdStr);
//                                        CuccPosServiceUtils.setExtParamValue(prodInstFunc, sceneInstId, LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + prodInstFunc.getSpecId(), attrGroupInstIdStr);
//                                        operateSceneInstService.addProdInstFunc(sceneInstId, prodInstFunc);
//                                    }
//                                }
//                            }
//                        }
//                        catch (Exception e) {
//                            operateSceneInstService.putExtParameter(sceneInstId, "loadingTariffPlanFlag", "F");
//                            LOGGER.info("资费计划处理失败："+e.getMessage());
//                        }
//                        finally {
//                            operateSceneInstService.removeExtParameter(sceneInstId, "loadingTariffPlanFlag");
//                            KiteTransactionUtils.commit();
//                        }
//                    }));
//            }

        }
    }
    private void asyncservInfos(String custId, String sceneInstId, Map<String, List<KitePosAttrDTO>> servAttrGroupMap, String parentInstId, String specId, LoginInfo loginInfo, KiteProdInst accessProdInst, String staffId) {

        CompletableFuture.runAsync(
            FunctionWrapper.wrapLoginInfoAndTrans(() -> {
                try {
                    while (KiteMapUtils.isNotEmpty(servAttrGroupMap)) {
                        Map<String, Object> servAttrGroup = getOneAndRemove(servAttrGroupMap);
                        String attrGroupInstIdStr = (String) servAttrGroup.get("key");
                        List<KitePosAttrDTO> prodInstFcunAttrs = (List<KitePosAttrDTO>) servAttrGroup.get("value");
                        DataResult<ProdFuncVO> result = operateSceneFuncProdInstService.addFuncProdInstWithoutRuleTrigger(sceneInstId, parentInstId, specId, custId, staffId);
                        KiteProdInstFunc prodInstFunc = this.querySceneInstService.getProdInstFunc(custId, result.getResultObject().getProdInstId());
                        this.setProdInstAttrValue(sceneInstId, null, prodInstFunc, accessProdInst, prodInstFcunAttrs, loginInfo);
                        prodInstFcunAttrs.removeIf(attr -> KiteStringUtils.equalsAny(attr.getCode(), "200003681","200004024"));
                        boolean isDeleteChangeType = false;
                        String changeType = dealFunProdInstActionType(prodInstFcunAttrs);
                        if (KiteStringUtils.isNotEmpty(changeType)) {
                            // 还原他的动作
                            if (KiteStringUtils.equals(ChangeTypeUtils.CHANGE_TYPE_D, changeType)) {
                                isDeleteChangeType = true;
                                operateSceneFuncProdInstService.removeFuncProdInst(sceneInstId, parentInstId, prodInstFunc.getProdInstId(), custId, staffId);
                            }
                            else {
                                prodInstFunc.setActionType(ChangeTypeUtils.getActionType(changeType));
                            }
                        }
                        if (!isDeleteChangeType) {
                            // 设置对端的属性组实例ID
                            prodInstFunc.setExtProdInstId(attrGroupInstIdStr);
                            //prodInstFunc.setExtParamValue(LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + prodInstFunc.getSpecId(), attrGroupInstIdStr);
                            CuccPosServiceUtils.setExtParamValue(prodInstFunc, sceneInstId, LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + prodInstFunc.getSpecId(), attrGroupInstIdStr);
                            operateSceneInstService.addProdInstFunc(sceneInstId, prodInstFunc);
                        }
                    }
                }
                catch (Exception e) {
                    operateSceneInstService.putExtParameter(sceneInstId, "loadingTariffPlanFlag", "F");
                    LOGGER.info("资费计划处理失败："+e.getMessage());
                }
                finally {
                    operateSceneInstService.removeExtParameter(sceneInstId, "loadingTariffPlanFlag");
                    KiteTransactionUtils.commit();
                }
            }));

    }
    private Map<String, List<KitePosAttrDTO>> getSameFeePlanAttrGroups(String fieldName, String feePlanInstId, List<KitePosAttrDTO> attrGroups) {
        Map<String, List<KitePosAttrDTO>> result = new HashMap<>();
        for (KitePosAttrDTO attrGroup : attrGroups) {
            Map<String, Object> attrValueMap = JSONObject.parseObject(attrGroup.getValue(), Map.class);
            Iterator<String> it = attrValueMap.keySet().iterator();

            while (it.hasNext()) {
                String attrGroupInstId = it.next();
                JSONArray attrListValue = (JSONArray) attrValueMap.get(attrGroupInstId);
                List<KitePosAttrDTO> prodInstAttrs = JSONArray.parseArray(JSONArray.toJSONString(attrListValue), KitePosAttrDTO.class);
                if (prodInstAttrs.stream().anyMatch(attr -> KiteStringUtils.equals(fieldName, attr.getCode()) && KiteStringUtils.equals(feePlanInstId, attr.getValue()))) {
                    result.put(attrGroupInstId, prodInstAttrs);
                }
            }
        }
        return result;
    }

    private void initProdInstFunc(String sceneInstId, String custId, String staffId, String prodInstId, List<KitePosAttrDTO> attrGroups, List<KiteAttr> prodFuncIdAttrs, LoginInfo loginInfo) {
        // 如果附加产品没有属性组，只实例化一个附加产品，如果有属性组，根据属性组数量实例化并返填属性值
        if (KiteListUtils.isEmpty(attrGroups)) {
            return;
        }
        KiteSceneInst sceneInst = this.querySceneInstService.getSceneInst(sceneInstId);
        String serviceOfferId = sceneInst.getServiceOfferId();
        String aPostponeProdId = DcPublicCache.getPCode("20210326001","postponeProdId");
        KiteProdInst kiteProdInst = querySceneInstService.getProdInst(custId, prodInstId);
        //主产品的功能产品
        for (KitePosAttrDTO attrGroup : attrGroups) {
            String code = attrGroup.getCode();
            String prodFuncId = "";

            if(KiteStringUtils.equals(code, aPostponeProdId) && KiteStringUtils.isEqual(LocalServiceOfferConsts.SERVICE_OFFER_DELAY, serviceOfferId)){
                String zPostponeProdId = DcPublicCache.getCodea("20210326001", "postponeProdId");
                //KiteProdInst kiteProdInst = querySceneInstService.getProdInst(custId, prodInstId);
                String prodId = kiteProdInst.getProdId();
                List<ProdRelInfo> prodRelInfos = ProdRelCache.get(prodId);
                if(KiteListUtils.isNotEmpty(prodRelInfos)){
                    ProdRelInfo prodRelInfo = prodRelInfos.get(0);
                    zPostponeProdId = prodRelInfo.getzProdId();
                }
                prodFuncId = zPostponeProdId;
            }
            else{
                List<KiteAttr> prodFuncIdAttrs1 = prodFuncIdAttrs.stream().filter(attr -> KiteStringUtils.equals(ProductCache.get(attr.getGroupId()).getProdNbr(), attrGroup.getCode())).collect(Collectors.toList());
                if (KiteListUtils.isEmpty(prodFuncIdAttrs1)) {
                    continue;
                }
                prodFuncId = prodFuncIdAttrs1.get(0).getGroupId();
            }

            if (KiteObjectUtils.isEmpty(ProductCache.get(prodFuncId))) {
                continue;
            }

            //功能产品实例初始化
            //String funcProdId = attrGroup.getCode();
            String attrValue = attrGroup.getValue();
            Map<String, Object> attrValueMap = JSONObject.parseObject(attrValue, Map.class);

            Iterator<String> it = attrValueMap.keySet().iterator();
            while (it.hasNext()) {
                String attrGroupInstId = it.next();
                JSONArray attrListValue = (JSONArray) attrValueMap.get(attrGroupInstId);
                List<KitePosAttrDTO> prodInstAttrs = JSONArray.parseArray(JSONArray.toJSONString(attrListValue), KitePosAttrDTO.class);
                if(KiteListUtils.isEmpty(prodInstAttrs)){
                    continue;
                }
                DataResult<ProdFuncVO> result = operateSceneFuncProdInstService.addFuncProdInst(sceneInstId, prodInstId, prodFuncId, custId, staffId);
                KiteProdInstFunc prodInstFunc = this.querySceneInstService.getProdInstFunc(custId, result.getResultObject().getProdInstId());

                this.setProdInstAttrValue(sceneInstId, null, prodInstFunc, kiteProdInst, prodInstAttrs, loginInfo);
                boolean isDeleteChangeType = false;
                String changeType = dealFunProdInstActionType(prodInstAttrs);
                if (KiteStringUtils.isNotEmpty(changeType)) {
                    // 还原他的动作
                    if (KiteStringUtils.equals(ChangeTypeUtils.CHANGE_TYPE_D, changeType)) {
                        isDeleteChangeType = true;
                        prodInstFunc.setExtProdInstId(attrGroupInstId);
                        //prodInstFunc.setExtParamValue(LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + prodInstFunc.getSpecId(), attrGroupInstId);
                        CuccPosServiceUtils.setExtParamValue(prodInstFunc, sceneInstId, LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + prodInstFunc.getSpecId(), attrGroupInstId);
                        operateSceneInstService.addProdInstFunc(sceneInstId, prodInstFunc);
                        operateSceneFuncProdInstService.removeFuncProdInst(sceneInstId, prodInstId, prodInstFunc.getProdInstId(), custId, staffId);
                    }
                    else {
                        prodInstFunc.setActionType(ChangeTypeUtils.getActionType(changeType));
                    }
                }
                if (!isDeleteChangeType) {
                    prodInstFunc.setExtProdInstId(attrGroupInstId);
                    //prodInstFunc.setExtParamValue(LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + prodInstFunc.getSpecId(), attrGroupInstId);
                    CuccPosServiceUtils.setExtParamValue(prodInstFunc, sceneInstId, LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + prodInstFunc.getSpecId(), attrGroupInstId);
                    operateSceneInstService.addProdInstFunc(sceneInstId, prodInstFunc);
                }
            }
        }
    }

    // 互联网大带宽附件属性处理
    private void initAttachmentProdInstInfo(String sceneInstId, String custId, String staffId, String prodInstId, List<KitePosAttrDTO> attrGroups, List<KiteAttr> attachmentsAttrs, LoginInfo loginInfo, KiteInst prodInst) {
        if (KiteListUtils.isEmpty(attrGroups)) {
            return;
        }
        KiteSceneInst sceneInst = this.querySceneInstService.getSceneInst(sceneInstId);
        //主产品的功能产品
        for (KitePosAttrDTO attrGroup : attrGroups) {
            String code = attrGroup.getCode();
            if (KiteStringUtils.equals(code, "300000203")) {
                String changeType_300000203 = attrGroup.getChangeType();//整个附件的变更的动作
                String actionType_300000203 = KiteStringUtils.isEmpty(changeType_300000203) ? ActionType.K.name() : ChangeTypeUtils.getActionType(changeType_300000203).name();
                //互联网产品大带宽附件实例初始化
                String attrValue = attrGroup.getValue();
                Map<String, Object> attrValueMap = JSONObject.parseObject(attrValue, Map.class);
                Iterator<String> it = attrValueMap.keySet().iterator();
                List jsonArray = new ArrayList();
                // 保存附件对应的生失效时间
                Map<String, Object> originAttachments = new HashMap<>();
                while (it.hasNext()) {
                    String attrGroupInstId = it.next();
                    Map jsonParam = new HashMap();
                    JSONArray attrListValue = (JSONArray) attrValueMap.get(attrGroupInstId);
                    List<KitePosAttrDTO> prodInstAttrs = JSONArray.parseArray(JSONArray.toJSONString(attrListValue), KitePosAttrDTO.class);
                    if (KiteListUtils.isEmpty(prodInstAttrs)) {
                        continue;
                    }
                    String actionType = "";
                    for (KitePosAttrDTO prodInstAttr : prodInstAttrs) {
                        if (KiteStringUtils.equals(prodInstAttr.getCode(), "210004325")) {   //附件类型
                            List<KiteAttr> attachmentsTypeAttr = prodInst.listAttrs().stream().filter(attr -> KiteStringUtils.equals(attr.getFieldName(), "210004325")).collect(Collectors.toList());
                            attachmentsTypeAttr.forEach(attr -> {
                                jsonParam.put("fileTypeName",attr.getAttrValues().stream().filter(attrValueList ->KiteStringUtils.equalsAny(prodInstAttr.getValue(),attrValueList.getAttrValue())).collect(Collectors.toList()).get(0).getAttrValueName());
                            });
                        }
                        if (KiteStringUtils.equals(prodInstAttr.getCode(), "210004326")) {  //附件名称
                            String fileType = prodInstAttr.getValue().substring(KiteStringUtils.lastIndexOf(prodInstAttr.getValue(), ".") + 1);
                            String fileName =  prodInstAttr.getValue().substring(KiteStringUtils.lastIndexOf( prodInstAttr.getValue(), "/") + 1, KiteStringUtils.indexOf( prodInstAttr.getValue(), "."));
                            jsonParam.put("type", fileType);
                            jsonParam.put("fileName", fileName);
                        }
                        if (KiteStringUtils.equals(prodInstAttr.getCode(), "210004327")) {  //附件URL
                            jsonParam.put("attachmentUrl", prodInstAttr.getValue());
                        }
                        if (KiteStringUtils.equals(prodInstAttr.getCode(), "210004328")) {  //附件上传时间
                            jsonParam.put("createDate", prodInstAttr.getValue());
                        }
                        if (KiteStringUtils.equals(prodInstAttr.getCode(), "changeType")&&KiteStringUtils.isNotEmpty(prodInstAttr.getValue())) {  //还原附件状态
                            //如果有changeType 按changeType值还原附件状态
                            String changeType = prodInstAttr.getValue();
                            actionType = ChangeTypeUtils.getActionType(changeType).name();
                            jsonParam.put("actionType",actionType);
                        }
                    }
                    originAttachments.put(attrGroupInstId, prodInstAttrs);
                    if(KiteStringUtils.isEmpty(actionType)){
                        actionType = ActionType.K.name();
                        jsonParam.put("actionType",actionType);
                    }
                    jsonParam.put("attrGroupInstId",attrGroupInstId);//保存还原回来的实例ID
                    if(!KiteStringUtils.equals(actionType,ActionType.A.name())){//不是新增状态的附件还原初始值
                        jsonParam.put("originValue", JSONArray.toJSONString(jsonParam));
                    }
                    jsonArray.add(jsonParam);
                }
                attachmentsAttrs.stream().forEach(attr->{
                    if(KiteStringUtils.equals(attr.getFieldName(), "300000203")){
                        attr.setValue(JSONObject.toJSONString(jsonArray));
                        if(!KiteStringUtils.equals(ActionType.A.name(),actionType_300000203)){
                            attr.setOriginValue(JSONObject.toJSONString(jsonArray));
                        }
                        attr.setValueDesc(JSONObject.toJSONString(jsonArray));
                    }
                });
                operateSceneInstService.putExtParameter(sceneInstId, "DIA_ORIGIN_ATTACHMENTS", originAttachments);
            }
        }
    }
    @Override
    public boolean initAttachmentFromAttrGrp(KiteProdInst prodInst,List<KitePosAttrDTO> attrGroups,String offerId,String sceneInstId){
        KiteAttr groupAttr = prodInst.getAttr("ATTAGRP");
        if(!Objects.nonNull(groupAttr)) {
            return true;
        }
        String groupId = groupAttr.getDefaultValue();//获取产品下配置的组id
        if(KiteStringUtils.isEmpty(groupId)) {
            return true;//没有配置则不用处理
        }
        KitePosAttrDTO group = null;
        //KitePosAttrDTO group = attrGroups.stream().filter(ag -> KiteStringUtils.equals(ag.getCode(), groupId)).findFirst().get();
        Iterator<KitePosAttrDTO> iterator = attrGroups.iterator();
        //找到附件组 删除附件组
        while (iterator.hasNext()){
            KitePosAttrDTO tempDTO = iterator.next();
            if(KiteStringUtils.equals(groupId,tempDTO.getCode())){
                operateInstAttrService.setAttrValue(prodInst, groupId, prodInst.getAttr(groupId).getDefaultValue(), sceneInstId, null);
                group = tempDTO;
                iterator.remove();
            }
        }
        List<Map.Entry<String, KiteAttr>> cfCodes = prodInst.getAttrMap().entrySet().stream().filter(en -> KiteStringUtils.equals(en.getValue().getAttrValueTypeId(), "98F")).collect(Collectors.toList());
        if(group == null||KiteStringUtils.equalsAny(group.getValue(),"","{}")){//若没有获取到属性组报文 判断是不是旧格式
            cfCodes.forEach(cfcode ->{
                String ordStr = cfcode.getValue().getValue();
                if(KiteStringUtils.isNotEmpty(ordStr)&&ordStr.contains("orderAttachArr")){
                    JSONObject ordJson = JSONObject.parseObject(ordStr);
                    JSONArray ordArry = ordJson.getJSONArray("orderAttachArr");
                    JSONArray cfHt = new JSONArray();
                    ordArry.forEach(it->{
                        JSONObject ordObj = JSONObject.parseObject(JSON.toJSONString(it));
                        JSONObject tempObj = new JSONObject();
                        tempObj.put("attachmentUrl",ordObj.get("fileName"));
                        String tempType = ordObj.getString("fileType");
                        String fileName = ordObj.getString("backFileName");
                        if(KiteStringUtils.isNotEmpty(tempType)){
                            fileName = fileName.replace(SymbolConsts.PERIOD+ordObj.getString("fileType"),"");
                        }
                        tempObj.put("fileName",fileName);
                        tempObj.put("fileTypeName",ordObj.get("backFileName"));
                        tempObj.put("fileTypeIcon",ordObj.get("fileTypeIcon"));
                        tempObj.put("createDate",ordObj.get("uploadTime"));
                        tempObj.put("type",ordObj.get("fileType"));
                        cfHt.add(tempObj);
                    });
                    String cfHtStr = JSON.toJSONString(cfHt);
                    prodInst.getAttr(cfcode.getKey()).setValue(cfHtStr);
                    prodInst.getAttr(cfcode.getKey()).setValueDesc(cfHtStr);
                }
            });
            return true;
        }
        String htFldName = "";
        boolean isShowMore = cfCodes.size()>1;
        if(!isShowMore){
           htFldName = cfCodes.get(0).getKey();
        }
        String value = group.getValue();
        JSONObject jsonObjectVal = JSON.parseObject(value);
        if(jsonObjectVal==null||jsonObjectVal.size()==0) {
            return true;
        }
        // 保存附件对应的生失效时间
        Map<String, Object> originAttachments = new HashMap<>();
        for (Entry<String,Object> entry:jsonObjectVal.entrySet()) {//遍历附件
            JSONArray attrListValue = (JSONArray) entry.getValue();
            List<KitePosAttrDTO> prodInstAttrs = JSONArray.parseArray(JSONArray.toJSONString(attrListValue), KitePosAttrDTO.class);
            Map jsonParam = new HashMap();
            String actionType = "";
            for(KitePosAttrDTO prodInstAttr:prodInstAttrs){
                String fieldName = prodInstAttr.getCode();
                switch (fieldName){
                    case "210004325":
                        KiteAttr attachmentsTypeAttr = prodInst.getAttr(fieldName);
                        jsonParam.put("fileTypeName",attachmentsTypeAttr.getAttrValues().stream().filter(attrValueList ->KiteStringUtils.equals(prodInstAttr.getValue(),attrValueList.getAttrValue())).findFirst().get().getAttrValueName());
                        if(isShowMore){//分多组展示查找文件类型对应的字段名
                            List<DcPublic> tempDc = DcPublicCache.getByPkey("20210506002", offerId);
                            if(KiteListUtils.isNotEmpty(tempDc)){
                                DcPublic dc = tempDc.stream().filter(it -> KiteStringUtils.equals(it.getCodea(), prodInstAttr.getValue())).findFirst().orElse(null);
                                if(Objects.nonNull(dc)) {
                                    htFldName = dc.getPcode();
                                }
                            }
                            //htFldName ="200002641";
                        }
                        break;
                    case "210004326":
                        String fileType = prodInstAttr.getValue().substring(KiteStringUtils.lastIndexOf(prodInstAttr.getValue(), ".") + 1);
                        String fileName =  prodInstAttr.getValue().substring(KiteStringUtils.lastIndexOf( prodInstAttr.getValue(), "/") + 1, KiteStringUtils.indexOf( prodInstAttr.getValue(), "."));
                        jsonParam.put("type", fileType);
                        jsonParam.put("fileName", fileName);
                        break;
                    case "210004327":
                        jsonParam.put("attachmentUrl", prodInstAttr.getValue());
                        break;
                    case "210004328":
                        jsonParam.put("createDate", prodInstAttr.getValue());
                        break;
                    case "changeType":
                        //如果有changeType 按changeType值还原附件状态
                        String changeType = prodInstAttr.getValue();
                        actionType = ChangeTypeUtils.getActionType(changeType).name();
                        jsonParam.put("actionType",actionType);
                    default:break;
                }
            }
            if(KiteMapUtils.isNotEmpty(jsonParam)){
                if(KiteStringUtils.isEmpty(actionType)){//如果为空说明没有返回changeType还原为不变
                    actionType = ActionType.K.name();
                    jsonParam.put("actionType",actionType);
                }
                jsonParam.put("attrGroupInstId",entry.getKey());//保存还原回来的实例ID
                //如果附件状态不是新增 还原初始值
                if(!KiteStringUtils.equals(actionType,ActionType.A.name())){
                    originAttachments.put(entry.getKey(), prodInstAttrs);
                    jsonParam.put("originValue", JSONArray.toJSONString(jsonParam));
                }
                String htAtta = prodInst.getAttr(htFldName).getValue();
                JSONArray htAttaArr = new JSONArray();
                if(KiteStringUtils.isNotEmpty(htAtta)){
                    htAttaArr = JSON.parseArray(htAtta);
                }
                htAttaArr.add(jsonParam);
                htAtta = JSON.toJSONString(htAttaArr);
                prodInst.getAttr(htFldName).setValue(htAtta);
                prodInst.getAttr(htFldName).setValueDesc(htAtta);
                prodInst.getAttr(htFldName).setOriginValue(htAtta);
            }
            operateSceneInstService.putExtParameter(sceneInstId + "_" + offerId ,"DIA_ORIGIN_ATTACHMENTS", originAttachments);
        }
        return false;
    }
    private String dealFunProdInstActionType(List<KitePosAttrDTO> prodInstAttrs) {
        if (KiteListUtils.isEmpty(prodInstAttrs)) {
            return "";
        }
        prodInstAttrs.removeIf(attrs -> KiteStringUtils.equalsAny(attrs.getCode(), "masterSla", "CUST_TYPE", "changeType"));
        //新增属性个数
        int addCount = 0;
        // 删除属性个数
        int delCount = 0;
        // 不变属性个数
        int noChange = 0;
        // 属性中是否存在changeType属性值
        boolean flag = false;
        for (KitePosAttrDTO instAttr : prodInstAttrs) {
            if (KiteStringUtils.isEmpty(instAttr.getChangeType())) {
                continue;
            }
            flag = true;
            if (KiteStringUtils.isEqual(instAttr.getChangeType(), ChangeTypeUtils.CHANGE_TYPE_A)) {
                addCount = addCount + 1;
                continue;
            }
            if (KiteStringUtils.isEqual(instAttr.getChangeType(), ChangeTypeUtils.CHANGE_TYPE_D)) {
                delCount = delCount + 1;
                continue;
            }
            if (KiteStringUtils.isEqual(instAttr.getChangeType(), ChangeTypeUtils.CHANGE_TYPE_K)) {
                noChange = noChange + 1;
                continue;
            }
        }
        if (flag) {
            if (addCount == prodInstAttrs.size()
                || (delCount + addCount == prodInstAttrs.size() && delCount < addCount)) {
                return ChangeTypeUtils.CHANGE_TYPE_A;
            }
            if (delCount == prodInstAttrs.size()
                || (delCount + noChange == prodInstAttrs.size() && noChange < delCount)) {
                return ChangeTypeUtils.CHANGE_TYPE_D;
            }
            if (noChange == prodInstAttrs.size()
                || (delCount + noChange == prodInstAttrs.size() && noChange > delCount)
                || (addCount + noChange == prodInstAttrs.size() && noChange > addCount)) {
                return ChangeTypeUtils.CHANGE_TYPE_K;
            }
            return ChangeTypeUtils.CHANGE_TYPE_M;
        }
        else {
            // 没有changetype时返回空
            return ChangeTypeUtils.CHANGE_TYPE_K;
        }
    }
    private void initProdOtherAttrs(String sceneInstId, String custId, String prodInstId, List<KitePosAttrDTO> attrGroups, List<KiteAttr> connectTypeOtherAttrs, LoginInfo loginInfo) {
        if (KiteListUtils.isEmpty(attrGroups)) {
            return;
        }
        KiteSceneInst sceneInst = this.querySceneInstService.getSceneInst(sceneInstId);
        String serviceOfferId = sceneInst.getServiceOfferId();
        String aPostponeProdId = DcPublicCache.getPCode("20210326001","postponeProdId");

        KiteProdInst kiteProdInst = this.querySceneInstService.getProdInst(custId, prodInstId);
        for (KitePosAttrDTO attrGroup : attrGroups) {
            String code = attrGroup.getCode();
            if (KiteStringUtils.isEqual(LocalServiceOfferConsts.SERVICE_OFFER_DELAY, serviceOfferId) && KiteStringUtils.isEqual(code,aPostponeProdId)) {
                continue;
            }
            String attrValue = attrGroup.getValue();
            Map<String, Object> attrValueMap = JSONObject.parseObject(attrValue, Map.class);
            Iterator<String> it = attrValueMap.keySet().iterator();
            String attrGroupInstId = null;
            //遍历map取key最大的值
            while (it.hasNext()) {
                if (KiteStringUtils.isEmpty(attrGroupInstId)) {
                    attrGroupInstId = it.next();
                } else {
                    String nextAttrGroupInstId = it.next();
                    if (KiteStringUtils.compare(attrGroupInstId, nextAttrGroupInstId) < 0){
                        attrGroupInstId = nextAttrGroupInstId;
                    }
                }
            }
            if (KiteStringUtils.isNotEmpty(attrGroupInstId)) {
                //kiteProdInst.setExtParamValue(LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + code, attrGroupInstId);
                CuccPosServiceUtils.setExtParamValue(kiteProdInst, sceneInst.getSceneInstId(), LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + code, attrGroupInstId);

                JSONArray attrListValue = (JSONArray) attrValueMap.get(attrGroupInstId);
                List<KitePosAttrDTO> prodInstOtherAttrs = JSONArray.parseArray(JSONArray.toJSONString(attrListValue), KitePosAttrDTO.class);
                this.setProdInstAttrValue(sceneInstId, null, kiteProdInst, kiteProdInst, prodInstOtherAttrs, loginInfo);
            }
        }
    }


    @Override
    @KiteTransactional
    public void initAddRoleOfferInst(String sceneInstId, String custId, String staffId, List<KitePosGoodsDTO> offerInsts, LoginInfo loginInfo) {
        if (KiteListUtils.isEmpty(offerInsts)) {
            return;
        }
        List<KitePosGoodsDTO> addRoleOfferInsts = offerInsts.stream().filter(offerInst -> GoodsInfoTransfer.isAddRoleOffer(offerInst.getCode(), offerInst.getCatagoryId())).collect(Collectors.toList());
        if (KiteListUtils.isEmpty(addRoleOfferInsts)) {
            return;
        }
        List<String> addRoleInstanceId = new ArrayList<>();
        //String parentInstId = querySceneInstService.getSceneInst(sceneInstId).getRootInstId();
        for (KitePosGoodsDTO offerInst : addRoleOfferInsts) {
            // 追加配件场景还原时，实物附加商品不还原实例
            if (KiteStringUtils.isEqual("2020", querySceneInstService.getSceneInst(sceneInstId).getServiceOfferId())) {
                if (GoodsHelper.isMaterialOffer(offerInst.getCode())) {
                    continue;
                }
            }

            String parentInstId = null;
            String parentOfferId = null;
            String parentOfferName = null;
            // 获取附加商品的主商品
            List<KitePosGoodsDTO> parentOfferInsts = offerInsts.stream().filter(offerInst1 -> KiteStringUtils.equals(offerInst.getParentInstId(), offerInst1.getInstanceId())).collect(Collectors.toList());
            if (!KiteListUtils.isEmpty(parentOfferInsts)) {
                // 主商品的商品ID
                String mainOfferId = parentOfferInsts.get(0).getCode();
                // 主商品实例
                List<KiteOfferInst> mainOfferInsts = this.querySceneInstService.listMainOfferInsts(sceneInstId, mainOfferId);
                if (!KiteListUtils.isEmpty(mainOfferInsts)) {
                    parentInstId = mainOfferInsts.get(0).getOfferInstId();
                    parentOfferId = mainOfferInsts.get(0).getAttrValue("saleGoodsCode");
                    parentOfferName = mainOfferInsts.get(0).getAttrValue("saleGoodsName");
                }
            }
            String offerId = offerInst.getCode();
            // 有必选关系的已经初始化了,先取一次
            List<KiteOfferInst> addRoleInsts = this.querySceneInstService.listInsts(sceneInstId, Collections.singletonList(InstType.MAIN_OFFER_INST), offerId);
            List<KitePosProductDTO> products = offerInst.getProducts();
            for (KitePosProductDTO product : products) {
                // 一个产品实例对应一个附加产品销售品实例,进来先置空
                String additionalOfferInstId = null;
                if (KiteListUtils.isNotEmpty(addRoleInsts) ) {
                    for (KiteOfferInst addRoleInst: addRoleInsts) {
                        if (addRoleInstanceId.contains(addRoleInst.getOfferInstId())) {
                            continue;
                        }
                        additionalOfferInstId = addRoleInst.getOfferInstId();
                    }
                }
                List<KitePosAttrDTO> kitePosAttrDTOAttas = new ArrayList<>();
                List<KitePosAttrDTO> productAttrs = product.getAttrs();
                List<KitePosAttrDTO> attrGroups = productAttrs.stream().filter(attr -> LocalKeyConsts.ATTR_TYPE_GROUP.equals(attr.getType())).collect(Collectors.toList());
                Iterator<KitePosAttrDTO> attrGroupsIt = attrGroups.iterator();
                while (attrGroupsIt.hasNext()){//过滤附件属性组
                    KitePosAttrDTO tempDto = attrGroupsIt.next();
                    if(KiteListUtils.isNotEmpty(DcPublicCache.getByPkey("20210506",tempDto.getCode()))){
                        kitePosAttrDTOAttas.add(tempDto);
                        attrGroupsIt.remove();
                    }
                }
                // 如果附加产品没有属性组，只实例化一个附加产品，如果有属性组，根据属性组数量实例化并返填属性值
                if (!KiteListUtils.isEmpty(attrGroups)) {
                    for (KitePosAttrDTO attrGroup : attrGroups) {
                        //附加产品实例初始化
                        String attrValue = attrGroup.getValue();
                        Map<String, Object> attrValueMap = JSONObject.parseObject(attrValue, Map.class);
                        Iterator it = attrValueMap.keySet().iterator();
                        while (it.hasNext()) {
                            KiteOfferInst kiteOfferInst = null;
                            if (KiteStringUtils.isEmpty(additionalOfferInstId)){
                                //没有实例化，需要进行实例化再设置属性
                                kiteOfferInst = operateSceneOfferInstService.addOfferInst(sceneInstId, parentInstId, offerId, offerInst.getCatagoryId(), custId, staffId).getResultObject();
                            }
                            else {
                                kiteOfferInst = querySceneInstService.getOfferInst(custId, additionalOfferInstId);
                            }

                            // 已实例化可选包id的集合
                            addRoleInstanceId.add(kiteOfferInst.getOfferInstId());
                            CuccPosServiceUtils.setExtParamValue(kiteOfferInst, sceneInstId, "saleGoodsCode", parentOfferId);
                            CuccPosServiceUtils.setExtParamValue(kiteOfferInst, sceneInstId, "saleGoodsName", parentOfferName);
                            CuccPosServiceUtils.setExtParamValue(kiteOfferInst, sceneInstId, "startDate", offerInst.getStartDate());
                            CuccPosServiceUtils.setExtParamValue(kiteOfferInst, sceneInstId, "endDate", offerInst.getEndDate());

                            List<KiteInstRelDTO> instRels = this.querySceneInstService.listInstRelsByAInst(custId, InstType.MAIN_OFFER_INST, kiteOfferInst.getOfferInstId(), InstType.PROD_INST);
                            String prodInstId = instRels.get(0).getzInstId();
                            KiteProdInst prodInst = this.querySceneInstService.getProdInst(custId, prodInstId);
                            // 后面转单组装属性组时用到
                            Map<String, KitePosAttrDTO> orgAttrGroupMap = querySceneInstService
                                .getExtParameterValue(sceneInstId, "attrGroupMap_".concat(prodInstId));
                            if (Objects.nonNull(orgAttrGroupMap)) {
                                orgAttrGroupMap.put(attrGroup.getCode(), attrGroup);
                            }
                            else {
                                Map<String, KitePosAttrDTO> attrGroupMap = new HashMap<>();
                                attrGroupMap.put(attrGroup.getCode(), attrGroup);
                                operateSceneInstService
                                    .putExtParameter(sceneInstId, "attrGroupMap_".concat(prodInstId), attrGroupMap);
                            }
                            String attrGroupInstId = (String) it.next();
                            JSONArray attrListValue = (JSONArray) attrValueMap.get(attrGroupInstId);
                            List<KitePosAttrDTO> prodInstAttrs = JSONArray.parseArray(JSONArray.toJSONString(attrListValue), KitePosAttrDTO.class);
                            this.setProdInstAttrValue(sceneInstId, product.getDestItemId(), prodInst, prodInst, prodInstAttrs, loginInfo);
                            //还原动作
                            String changeType = dealFunProdInstActionType(prodInstAttrs);
                            if(!KiteStringUtils.isEqual(ChangeTypeUtils.CHANGE_TYPE_A,changeType)){
                                this.setExtOfferInstId(sceneInstId, offerInst.getDestItemId(), custId, kiteOfferInst);
                            }
                            if (KiteStringUtils.isNotEmpty(changeType)) {
                                prodInst.setExtProdInstId(attrGroupInstId);
                                //prodInst.setExtParamValue(LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + prodInst.getSpecId(), attrGroupInstId);
                                CuccPosServiceUtils.setExtParamValue(prodInst, sceneInstId, LocalKeyConsts.PREFIX_ATTR_GROUP_INST_ID + prodInst.getSpecId(), attrGroupInstId);
                                // 还原他的动作
                                if (KiteStringUtils.equals(ChangeTypeUtils.CHANGE_TYPE_D, changeType)) {
                                    // 还原产品实例动作
                                    operateSceneProdInstService.removeProdInst(sceneInstId, prodInst.getProdInstId());
                                    String offerType = OfferCache.get(kiteOfferInst.getOfferId()).getOfferType();
                                    // 还原销售品实例动作
                                    operateSceneOfferInstService.removeOffer(sceneInstId, custId, kiteOfferInst.getOfferInstId(), offerType);
                                }
                                else {
                                    prodInst.setActionType(ChangeTypeUtils.getActionType(changeType));
                                    operateSceneInstService.addProdInst(sceneInstId, prodInst);
                                    kiteOfferInst.setActionType(ChangeTypeUtils.getActionType(changeType));
                                    operateSceneInstService.addMainOfferInst(sceneInstId, kiteOfferInst);
                                }
                            }
                        }
                    }
                }
                else {
                    List<KitePosAttrDTO> prodInstAttrs = product.getAttrs();
                    KiteOfferInst kiteOfferInst = null;
                    if (KiteStringUtils.isEmpty(additionalOfferInstId)){
                        //没有实例化，需要进行实例化再设置属性
                        kiteOfferInst = operateSceneOfferInstService.addOfferInst(sceneInstId, parentInstId, offerId, offerInst.getCatagoryId(), custId, staffId).getResultObject();
                    }
                    else {
                        kiteOfferInst = querySceneInstService.getOfferInst(custId, additionalOfferInstId);
                    }
                    // 已实例化可选包id的集合
                    addRoleInstanceId.add(kiteOfferInst.getOfferInstId());
                    CuccPosServiceUtils.setExtParamValue(kiteOfferInst, sceneInstId, "saleGoodsCode", parentOfferId);
                    CuccPosServiceUtils.setExtParamValue(kiteOfferInst, sceneInstId, "saleGoodsName", parentOfferName);
                    CuccPosServiceUtils.setExtParamValue(kiteOfferInst, sceneInstId, "startDate", offerInst.getStartDate());
                    CuccPosServiceUtils.setExtParamValue(kiteOfferInst, sceneInstId, "endDate", offerInst.getEndDate());

                    List<KiteProdInst> prodInsts = this.querySceneInstService.listProdInstsFromOfferInst(custId, kiteOfferInst.getOfferInstId());
                    /*List<KiteInstRelDTO> instRels = this.querySceneInstService.listInstRelsByAInst(custId, InstType.MAIN_OFFER_INST, kiteOfferInst.getOfferInstId(), InstType.PROD_INST);
                    String prodInstId = instRels.get(0).getzInstId();*/
                    if (KiteListUtils.isEmpty(prodInsts)) {
                        return;
                    }
                    KiteProdInst prodInst = prodInsts.get(0);
                    this.setProdInstAttrValue(sceneInstId, product.getDestItemId(), prodInst, prodInst, prodInstAttrs, loginInfo);
                    if(Objects.nonNull(kitePosAttrDTOAttas)&&!this.initAttachmentFromAttrGrp(prodInst,kitePosAttrDTOAttas,offerId,sceneInstId)){
                        operateSceneInstService.addProdInst(sceneInstId,prodInst);
                    }
                    //还原动作
                    String changeType = dealFunProdInstActionType(prodInstAttrs);
                    if (KiteListUtils.isEmpty(prodInstAttrs) && KiteStringUtils.isEmpty(changeType)
                        && KiteStringUtils.isNotEmpty(product.getChangeType())) {
                        changeType = product.getChangeType();
                    }
                    if(!KiteStringUtils.isEqual(ChangeTypeUtils.CHANGE_TYPE_A,changeType)){
                        this.setExtOfferInstId(sceneInstId, offerInst.getDestItemId(), custId, kiteOfferInst);
                    }
                    if (KiteStringUtils.isNotEmpty(changeType)) {
                        // 还原他的动作
                        if (KiteStringUtils.equals(ChangeTypeUtils.CHANGE_TYPE_D, changeType)) {
                            // 还原产品实例动作
                            operateSceneProdInstService.removeProdInst(sceneInstId, prodInst.getProdInstId());
                            // 还原销售品实例动作
                            String offerType = OfferCache.get(kiteOfferInst.getOfferId()).getOfferType();
                            operateSceneOfferInstService.removeOffer(sceneInstId, custId, kiteOfferInst.getOfferInstId(), offerType);
                        }
                        else {
                            prodInst.setActionType(ChangeTypeUtils.getActionType(changeType));
                            operateSceneInstService.addProdInst(sceneInstId, prodInst);
                            kiteOfferInst.setActionType(ChangeTypeUtils.getActionType(changeType));
                            operateSceneInstService.addMainOfferInst(sceneInstId, kiteOfferInst);
                        }
                    }
                }
            }
        }
    }

    private void setExtOfferInstId(String sceneInstId, String destItemId, String custId, KiteOfferInst kiteOfferInst) {
        KiteSceneInst sceneInst = this.querySceneInstService.getSceneInst(sceneInstId);
        // bizType可能是逗号分隔的多个二次类业务,新购时等于1001,追单等特殊流程有自己的serviceOfferId,结合bizType一起判断
        String bizType = querySceneInstService.getExtParameterValue(sceneInstId, "bizType");
        if (!KiteStringUtils.equalsAny(sceneInst.getServiceOfferId(),ServiceOfferConsts.SERVICE_OFFER_ORDER,LocalServiceOfferConsts.SERVICE_OFFER_ORDER_OPPER) && !"1001".equals(bizType)) {
            operateChangeService.setDeleteInstChange(sceneInst, kiteOfferInst, false, null, "");
            kiteOfferInst.setExtOfferInstId(destItemId);
            kiteOfferInst.setActionType(ActionType.K);
            kiteOfferInst.setOwnerCustId(custId);
            kiteOfferInst.setUseCustId(custId);
            kiteOfferInst.setOriginalActionType(ActionType.K);
        }
        operateSceneInstService.addInst(sceneInstId, kiteOfferInst);
    }

    private void setExtOfferInstId(String sceneInstId, KitePosGoodsDTO goods, String custId, KiteOfferInst kiteOfferInst) {
        KiteSceneInst sceneInst = this.querySceneInstService.getSceneInst(sceneInstId);
        // bizType可能是逗号分隔的多个二次类业务,新购时等于1001。追单等特殊流程有自己的serviceOfferId,结合bizType一起判断
        String bizType = querySceneInstService.getExtParameterValue(sceneInstId, "bizType");
        if (!KiteStringUtils.equalsAny(sceneInst.getServiceOfferId(),ServiceOfferConsts.SERVICE_OFFER_ORDER,LocalServiceOfferConsts.SERVICE_OFFER_ORDER_OPPER ) && !"1001".equals(bizType)) {
            operateChangeService.setDeleteInstChange(sceneInst, kiteOfferInst, false, null, "");
            kiteOfferInst.setExtOfferInstId(goods.getDestItemId());
            kiteOfferInst.setActionType(ActionType.K);
            kiteOfferInst.setOwnerCustId(custId);
            kiteOfferInst.setUseCustId(custId);
            kiteOfferInst.setOriginalActionType(ActionType.K);
            // 设备类增加创建时间
            try {
                kiteOfferInst.setCreateDate(DateUtils.parseStrToDate(goods.getStartDate(), DateUtils.LONG_PATTERN));
            } catch (Exception e) {
                // 异常不需要处理
            }
        }
        CuccPosServiceUtils.setExtParamValue(kiteOfferInst, sceneInstId, "saleGoodsCode", goods.getSaleGoodsCode());
        CuccPosServiceUtils.setExtParamValue(kiteOfferInst, sceneInstId, "saleGoodsName", goods.getSaleGoodsName());
        CuccPosServiceUtils.setExtParamValue(kiteOfferInst, sceneInstId, "startDate", goods.getStartDate());
        CuccPosServiceUtils.setExtParamValue(kiteOfferInst, sceneInstId, "endDate", goods.getEndDate());
        operateSceneInstService.addInst(sceneInstId, kiteOfferInst);
    }


    private void setExtProdInstId(String sceneInstId, String destItemId, String custId, KiteInst kiteInst) {
        KiteSceneInst sceneInst = this.querySceneInstService.getSceneInst(sceneInstId);
        // bizType可能是逗号分隔的多个二次类业务,新购时等于1001,追单等特殊流程有自己的serviceOfferId,结合bizType一起判断
        String bizType = querySceneInstService.getExtParameterValue(sceneInstId, "bizType");
        if (!KiteStringUtils.equalsAny(sceneInst.getServiceOfferId(),ServiceOfferConsts.SERVICE_OFFER_ORDER,LocalServiceOfferConsts.SERVICE_OFFER_ORDER_OPPER) && !"1001".equals(bizType)) {
            operateChangeService.setDeleteInstChange(sceneInst, kiteInst, false, null, "");
            kiteInst.setActionType(ActionType.K);
            kiteInst.setOwnerCustId(sceneInst.getCustId());
            kiteInst.setUseCustId(sceneInst.getCustId());
            kiteInst.setOriginalActionType(ActionType.K);
            if (InstType.PROD_INST.name().equals(kiteInst.getInstType().name())) {
                KiteProdInst prodInst = (KiteProdInst) kiteInst;
                prodInst.setExtProdInstId(destItemId);
                //operateSceneInstService.addProdInst(sceneInstId, (KiteProdInst) prodInst);
            }/* else {
                operateSceneInstService.addProdInstFunc(sceneInstId, (KiteProdInstFunc) kiteInst);
            }*/
        }
        operateSceneInstService.addInst(sceneInstId, kiteInst);
    }

    private void setProdInstAttrValue(String sceneInstId, String destItemId, KiteInst prodInst, KiteProdInst accProdInst, List<KitePosAttrDTO> prodInstAttrs, LoginInfo loginInfo) {
        if(KiteListUtils.isEmpty(prodInstAttrs)){
            this.setExtProdInstId(sceneInstId, destItemId, prodInst.getOwnerCustId(), prodInst);
            return;
        }

        List<KiteAttr> attrs = KiteListUtils.isNotEmpty(prodInst.listAttrs()) ?
            prodInst.listAttrs() :
            new ArrayList<>();
        attrs.sort(Comparator.comparing(attr -> NumberUtils.toInt(attr.getOrderId(), 0)));

        // 特殊参数，用于创建场景后设置场景参数用，createOfferSceneByWorkOrder方法结束前移除
        Map<String, Object> extParams = loginInfo.getUserInfo().getExtParams();
        String taskCode = KiteMapUtils.getString(extParams, "nodeCode");
        String serviceOfferId = KiteMapUtils.getString(extParams, "serviceOfferId");
        String goodsNodeId = KiteMapUtils.getString(extParams, "goodsNodeId");
        KiteSceneInst sceneInst = this.querySceneInstService.getSceneInst(sceneInstId);
        String askSource = sceneInst.getAskSource();
        if (KiteStringUtils.isEmpty(serviceOfferId)) {
            serviceOfferId = sceneInst.getServiceOfferId();
        }
        // MPLS-VPN 订单签订，已填写过的属性不可修改
        boolean orderSignNotEditAttrFlag = KiteStringUtils.equals(taskCode, "OrderSigned") && KiteStringUtils.equals(serviceOfferId, "1013") && KiteStringUtils.equals(goodsNodeId, ProdCateUtil.getSingleCateId(ProdCateUtil.MV_CODE));
        // 获取产品的历史属性 取接入产品产品编码和规格编码获取
        Map<String, KiteAttr> hisAttrMap = null;
        if(!KiteObjectUtils.isEmpty(accProdInst)){
            String accProdId = accProdInst.getSpecId();
            String accOfferId = null;
            List<KiteOfferInst> kiteOfferInsts = querySceneInstService.listMainOfferInstsByProdInstId(sceneInst.getCustId(), accProdInst.getProdInstId());
            if(KiteListUtils.isNotEmpty(kiteOfferInsts)){
                accOfferId = Optional.ofNullable(kiteOfferInsts.get(0)).map(KiteOfferInst::getSpecId).orElse(null);
            }
            if(!KiteStringUtils.isAnyEmpty(accOfferId,accProdId)){
                List<KiteAttr> hisAttr = ProdHisAttrCache.getByOfferId(accProdId,accOfferId);
                if(KiteListUtils.isNotEmpty(hisAttr)){
                    hisAttrMap = hisAttr.stream().collect(Collectors.toMap(KiteAttr::getFieldName, Function.identity()));
                }
            }
        }
        for (KiteAttr kiteAttr : attrs) {
            String fieldName = kiteAttr.getFieldName();
            //如果是传输计划则不更新
            if (KiteStringUtils.equalsAny(fieldName, "GRP_124", "200002981")) {
                continue;
            }
            // 追加订购/订购不需要还原apn标识，通信计划标识和资费计划标识和订购数量
            if (KiteStringUtils.equals(ServiceOfferConsts.SERVICE_OFFER_ORDER, serviceOfferId)
                && !KiteStringUtils.equals(LocalKeyConsts.ASK_SOURCE_ORDER, askSource)
                && KiteStringUtils.equalsAny(kiteAttr.getFieldName(), "200004129", "200004135", "200004128", "200004145", "200004146")) {
                continue;
            }/*else if (KeyConsts.IFTRUE_T.equals(querySceneInstService.getExtParameterValue(sceneInstId, LocalKeyConsts.ADD_ORDE))
                &&KiteStringUtils.equals(kiteAttr.getFieldName(),"200001696")
                &&!KiteStringUtils.equalsAny(taskCode, "OrderSigned","OrderAudit")) {
                continue;
            }*/
            List<KitePosAttrDTO> posAttrs = prodInstAttrs.stream().filter((attr) -> fieldName.equals(attr.getCode())).collect(Collectors.toList());
            //判断属性是否在极简端存在，存在则直接更新
            if (!KiteListUtils.isEmpty(posAttrs)) {
                KitePosAttrDTO attr = posAttrs.get(0);
                String value = attr.getValue();
                String valueDesc = attr.getValue();
                if (!KiteStringUtils.isEmpty(value) && KiteStringUtils.isIndexOf(KeyConsts.LOAD_ATTR_VALUE_CTRL, kiteAttr.getAttrValueTypeId(), "/")) {
                    // 注释掉，解决获取的valueDesc和AttrValues里面的描述对应不上
                    //valueDesc = Optional.ofNullable(AttrValueCache.getAttrValue(kiteAttr.getAttrId(), value))
                    //    .map(AttrValue::getAttrValueDesc).orElse("");
                    if (KiteListUtils.isEmpty(kiteAttr.getAttrValues())) {
                        List<AttrValue> attrValueList = AttrValueCache.get(kiteAttr.getAttrId());
                        if (KiteListUtils.isNotEmpty(attrValueList)) {
                            kiteAttr.setAttrValues(
                                KiteBeanUtils.copyPropsForList(attrValueList, KiteAttrValue.class));
                        }
                    }
                    List<KiteAttrValue> attrValues = kiteAttr.getAttrValues();
                    String finalValue = value;
                    if (KiteListUtils.isNotEmpty(attrValues)) {
                        KiteAttrValue kiteAttrValue = attrValues.stream().filter(attrValue -> KiteStringUtils.isEqual(finalValue, attrValue.getAttrValue())).
                            findFirst().orElse(null);
                        //现有枚举取不到值判断是否存在于历史枚举中 若存在添加到枚举中
                        if (Objects.nonNull(kiteAttrValue) && KiteStringUtils.isNotEmpty(kiteAttrValue.getAttrValueName())) {
                            valueDesc = kiteAttrValue.getAttrValueName();
                        } else if(KiteMapUtils.isNotEmpty(hisAttrMap)&&hisAttrMap.containsKey(kiteAttr.getFieldName())){
                            List<KiteAttrValue> attrValuesHis = hisAttrMap.get(kiteAttr.getFieldName()).getAttrValues();
                            KiteAttrValue kiteAttrValueHis = attrValuesHis.stream().filter(attrIt -> KiteStringUtils.equals(attrIt.getAttrValue(), finalValue)).findFirst().orElse(null);
                            if(Objects.nonNull(kiteAttrValueHis) && KiteStringUtils.isNotEmpty(kiteAttrValueHis.getAttrValueName())){
                                attrValues.add(kiteAttrValueHis);
                                kiteAttr.setAttrValues(attrValues);
                                valueDesc = kiteAttrValueHis.getAttrValueName();
                            }
                        }
                    } else {
                        if(KiteStringUtils.isEqual(fieldName, "210005009") && KiteStringUtils.isEqual(kiteAttr.getAttrValueTypeId(), "98F")) {
                            // 翻译收费单位名称
                            ChargeUnitQryDTO chargeUnitQryDTO = new ChargeUnitQryDTO();
                            List<ChargeUnitDTO> chargeUnits = ChargeUnitCache.get(chargeUnitQryDTO);
                            if(KiteListUtils.isNotEmpty(chargeUnits)) {
                                String chargeUnitName = chargeUnits.stream().filter(chargeUnit -> KiteStringUtils.isEqual(chargeUnit.getId(), finalValue)).findAny().map(ChargeUnitDTO::getName).orElse(null);
                                if(KiteStringUtils.isNotEmpty(chargeUnitName)) {
                                    valueDesc = chargeUnitName;
                                }
                            }
                        }
                    }
                }
                //附件处理
                if ("200004167".equals(fieldName) && KiteStringUtils.isNotEmpty(value)) {
                    String url = value;
                    String fileType = value.substring(KiteStringUtils.lastIndexOf(value, ".") + 1);
                    String fileName = value.substring(KiteStringUtils.lastIndexOf(value, "/") + 1, KiteStringUtils.indexOf(value, "."));
                    List jsonArray = new ArrayList();
                    Map jsonParam = new HashMap();
                    jsonParam.put("type", fileType);
                    jsonParam.put("fileName", fileName);
                    jsonParam.put("attachmentUrl", url);
                    jsonParam.put("fileType", "99");
                    jsonParam.put("fileTypeName", "其他");
                    jsonParam.put("createDate", DateUtil.formatCurDate("yyyy-MM-dd HH:mm:ss"));
                    jsonArray.add(jsonParam);
                    value = JSONObject.toJSONString(jsonArray);
                    valueDesc = JSONObject.toJSONString(jsonArray);
                }
                if (!KiteStringUtils.equals(attr.getChangeType(), ChangeTypeUtils.CHANGE_TYPE_A)) {
                    kiteAttr.setOriginValue(Optional.ofNullable(attr.getOriginValue()).orElse(attr.getValue()));
                }
                if(orderSignNotEditAttrFlag && KiteStringUtils.isNotBlank(value)) {
                    kiteAttr.setIsEdit("F");
                }
                // 属性为删除的时候，不还原
                if (!KiteStringUtils.equals(attr.getChangeType(), ChangeTypeUtils.CHANGE_TYPE_D)) {
                    operateInstAttrService.setAttrValue(prodInst, kiteAttr.getFieldName(), value, sceneInstId, CommonUtil.getAttrDataJson(TriggerStrategy.LOAD_VALUE));
                    //kiteAttr.setValue(value);
                    kiteAttr.setOldValue(value);
                    kiteAttr.setValueDesc(valueDesc);
                    kiteAttr.setEndDate(attr.getEndDate());
                }
                kiteAttr.setStartDate(attr.getStartDate());

                /*if (!KiteStringUtils.equals(KeyConsts.PROD_ATTR_SHOW_TYPE_H, kiteAttr.getShowType())) {
                    kiteAttr.setShowType(KeyConsts.PROD_ATTR_SHOW_TYPE_D);
                }*/
                prodInst.setAttr(kiteAttr);
            } else {
                // 订单补录详情（复用的签订初始化逻辑），不存在的属性，不赋值默认值，置为空
                String renderOrderType = querySceneInstService.getExtParameterValue(sceneInstId, "renderOrderType");
                if((KiteStringUtils.isNotEmpty(kiteAttr.getValue()) || KiteStringUtils.isNotEmpty(kiteAttr.getDefaultValue())) &&
                    KiteStringUtils.isEqual(taskCode, "OrderAddRecord") && !KiteStringUtils.isEqual(renderOrderType, "orderRejection") &&
                    KiteStringUtils.equalsAny(kiteAttr.getShowType(), KeyConsts.PROD_ATTR_SHOW_TYPE_D, KeyConsts.PROD_ATTR_SHOW_TYPE_M)) {
                    kiteAttr.setValue(null);
                    kiteAttr.setValueDesc(null);
                    kiteAttr.setOldValue(null);
                    kiteAttr.setOriginValue(null);
                    kiteAttr.setDefaultValue(null);
                    prodInst.setAttr(kiteAttr);
                }
            }
        }
        //operateInstAttrService.setListAttrValue(prodInst, prodInst.listAttrs(), sceneInstId, CommonUtil.getAttrDataJson(TriggerStrategy.LOAD_VALUE));
        this.setExtProdInstId(sceneInstId, destItemId, prodInst.getOwnerCustId(), prodInst);
    }

    @Override
    @KiteTransactional
    public void initAdditionalOfferInst(String sceneInstId, String custId, String staffId, List<KitePosGoodsDTO> kitePosGoodsDtos, LoginInfo loginInfo) {
        KiteSceneInst sceneInst = this.querySceneInstService.getSceneInst(sceneInstId);
        String sceneOperType = sceneInst.getOperType();

        for (KitePosGoodsDTO goods : kitePosGoodsDtos) {
            List<KiteOfferInst> offerInsts = this.querySceneInstService.listMainOfferInsts(sceneInstId, goods.getCode());
            if (KiteListUtils.isEmpty(offerInsts)) {
                if (!LocalKeyConsts.KITE_SCENE_INST_OPER_TYPE_1003.equals(sceneOperType)) {
                    continue;
                }
                // 核查转定商品变更场景，找同类型的产品-此方案不支持一个分类多个产品场景
                OfferAttr cateIdAttr = OfferAttrCache.get(goods.getCode()).stream().filter(attr -> "cateId".equals(attr.getFieldName())).findAny().get();
                if (Objects.nonNull(cateIdAttr)) {
                    String cateId = cateIdAttr.getDefaultValue();
                    offerInsts = this.querySceneInstService.listMainOfferInsts(sceneInstId).stream().filter(offerInst2 -> {
                        return KiteStringUtils.equals(cateId, offerInst2.getAttr("cateId").getDefaultValue());
                    }).collect(Collectors.toList());
                }
            }
            String offerInstId = offerInsts.get(0).getOfferInstId();

            List<KitePosProductDTO> products = goods.getProducts();
            if (KiteListUtils.isEmpty(products)) {
                continue;
            }
            List<KiteProdInst> prodInsts = this.querySceneInstService.listProdInstsByProdId(sceneInstId, products.get(0).getCode());

            List<KitePosGoodsFeeDTO> fees = !KiteListUtils.isEmpty(goods.getFees()) ? goods.getFees() : Lists.newArrayList();
            List<String> feeInstanceId = new ArrayList<>();
            List<KitePosGoodsFeeDTO> newFeesList = Lists.newArrayList();
            this.operateSceneInstService.putExtParameter(sceneInstId, offerInstId+"_oldPosGoodsFeeDto", newFeesList);
            Map<String, String> feeInstIdMap = new HashMap<>();
            //如果有资费没有加载到缓存中,重新加载一次
            this.refreshAdditionalOfferCacheIfNesscessary(goods.getCode(), fees, sceneInst.getProvinceNbr());
            for (KitePosGoodsFeeDTO fee : fees) {
                String additionalOfferInstId = null;
                List<KiteOfferInst> additionalOfferInsts = this.querySceneInstService.listInsts(sceneInstId, Collections.singletonList(InstType.ADDITIONAL_OFFER_INST), fee.getCode());
                if (KiteListUtils.isNotEmpty(additionalOfferInsts) ) {
                    for (KiteOfferInst additionalOfferInst: additionalOfferInsts) {
                        if (feeInstanceId.contains(additionalOfferInst.getOfferInstId())) {
                            continue;
                        }
                        additionalOfferInstId = additionalOfferInst.getOfferInstId();
                    }

                }
                if (KiteStringUtils.isEmpty(additionalOfferInstId)){
                    //没有实例化，需要进行实例化再设置属性
                    //兼容数据获取异常优化
                    if(KiteListUtils.isNotEmpty(prodInsts)){
                        additionalOfferInstId = addAdditionalOffer(sceneInstId, custId, prodInsts.get(0).getProdInstId(), fee.getCode(), offerInstId, KeyConsts.ADDITIONAL_OFFER_TYPE, true, loginInfo).getResultObject();

                    }
                }
                // 已实例化可选包id的集合
                feeInstanceId.add(additionalOfferInstId);

                // 落户老集客时，对于已有资费需要OrderDestItemId和ProductDestItemId
                if (KiteStringUtils.isNotEmpty(fee.getProductDestItemId()) || KiteStringUtils.isNotEmpty(fee.getOrderDestItemId())) {
                    KitePosGoodsFeeDTO newPosGoodsFee = new KitePosGoodsFeeDTO();
                    newPosGoodsFee.setCode(fee.getCode());
                    newPosGoodsFee.setDestItemId(fee.getDestItemId());
                    newPosGoodsFee.setOrderDestItemId(fee.getOrderDestItemId());
                    newPosGoodsFee.setProductDestItemId(fee.getProductDestItemId());
                    newFeesList.add(newPosGoodsFee);
                }
                //保留极简与订单中心实例Id的映射关系
                feeInstIdMap.put(additionalOfferInstId, fee.getInstanceId());
                //KiteOfferInst feeOfferInst = this.querySceneInstService.getMainOfferInstByAdditionalOfferId(sceneInstId, fee.getCode());
                KiteOfferInst feeOfferInst = this.querySceneInstService.getOfferInst(custId, additionalOfferInstId);
                // 还原场景实例动作
                String changeType = fee.getChangeType();
                List<KitePosAttrDTO> offerAttrInsts = fee.getAttrs();
                List<KitePosAttrDTO> tempPosAttrs = Lists.newArrayList(offerAttrInsts);
                List<KiteAttr> kiteAttrs = KiteListUtils.isNotEmpty(feeOfferInst.listAttrs()) ? feeOfferInst.listAttrs() : new ArrayList<>();
                //支持按顺序还原
                kiteAttrs.sort(Comparator.comparing(kiteAttr -> NumberUtils.toInt(kiteAttr.getOrderId(), 0)));
                for (KiteAttr kiteAttr : kiteAttrs) {
                    String fieldName = kiteAttr.getFieldName();
                    List<KitePosAttrDTO> posAttrs = offerAttrInsts.stream().filter((attr1) -> fieldName.equals(attr1.getCode())).collect(Collectors.toList());
                    if (!KiteListUtils.isEmpty(posAttrs)) {
                        KitePosAttrDTO attr = posAttrs.get(0);
                        String value = attr.getValue();
                        String valueDesc = attr.getValue();
                        if (KeyConsts.DROPDOWN.equals(kiteAttr.getAttrValueTypeId()) && !KiteStringUtils.isEmpty(value)) {
                            valueDesc = Optional
                                .ofNullable(AttrValueCache.getAttrValue(kiteAttr.getAttrId(), value)).map((attrValue) -> attrValue.getAttrValueDesc()).orElse("");
                        }

                        kiteAttr.setOldValue(value);
                        if (!KiteStringUtils.equals(attr.getChangeType(), ChangeTypeUtils.CHANGE_TYPE_A)) {
                            kiteAttr.setOriginValue(Optional.ofNullable(attr.getOriginValue()).orElse(attr.getValue()));
                        }
//                        kiteAttr.setValue(value);
                        operateInstAttrService.setAttrValue(feeOfferInst, kiteAttr.getFieldName(), value, sceneInstId, CommonUtil.getAttrDataJson(TriggerStrategy.LOAD_VALUE));
                        kiteAttr.setValueDesc(valueDesc);
                        if (!KiteStringUtils.isEqual(changeType, ChangeTypeUtils.CHANGE_TYPE_A)) {
                            if (KiteStringUtils.equalsAny(kiteAttr.getFieldName(), "200000173","200001735")){
                                kiteAttr.setIsEdit(KeyConsts.IFTRUE_T);
                            }
                            else {
                                kiteAttr.setIsEdit(KeyConsts.IFTRUE_F);
                            }

                        }
                        kiteAttr.setStartDate(attr.getStartDate());
                        kiteAttr.setEndDate(attr.getEndDate());
                        feeOfferInst.setAttr(kiteAttr);
                        tempPosAttrs.removeIf(posAttr -> fieldName.equals(posAttr.getCode()));
                    }
                }
                //属性在极简侧不存在，复制一个属性实例
                if (KiteListUtils.isNotEmpty(tempPosAttrs)) {
                    for (KitePosAttrDTO attr : tempPosAttrs) {
                        if (LocalKeyConsts.KITE_SCENE_INST_OPER_TYPE_1003.equals(sceneOperType)) {
                            continue;
                        }
                        // 从销售品规格中获取规格属性，如果规格属性没有，需要从接口获取，接口没有就不要新增属性实例
                        List<OfferAttr> offerAttrs = ProdFeeAttrCache.get(fee.getCode(), goods.getCode(), ContextUtil.getLoginInfo().getUserInfo().getPostProvinceNbr());
                        if (KiteListUtils.isNotEmpty(offerAttrs)) {
                            offerAttrs = offerAttrs.stream().filter((attr2) -> attr.getCode().equals(attr2.getFieldName())).collect(Collectors.toList());
                        }

                        if (KiteListUtils.isEmpty(offerAttrs)) {
                            continue;
                        }

                        KiteAttr copyAttr = new KiteAttr();
                        KiteBeanUtils.copyProperties(offerAttrs.get(0), copyAttr);
                        copyAttr.setAttrId(SeqUtils.getNext("SEQ_ATTR_ID"));
                        copyAttr.setInstId(feeOfferInst.getInstId());
                        copyAttr.setInstType(InstType.ADDITIONAL_OFFER_INST);
                        copyAttr.setFieldName(attr.getCode());
                        if (!KiteStringUtils.equals(attr.getChangeType(), ChangeTypeUtils.CHANGE_TYPE_A)) {
                            copyAttr.setOriginValue(Optional.ofNullable(attr.getOriginValue()).orElse(attr.getValue()));
                        }
                        copyAttr.setValue(attr.getValue());
                        copyAttr.setValueDesc(attr.getValue());
                        copyAttr.setStartDate(attr.getStartDate());
                        copyAttr.setEndDate(attr.getEndDate());
                        if (!KiteStringUtils.isEqual(changeType, ChangeTypeUtils.CHANGE_TYPE_A)) {
                            if (KiteStringUtils.equalsAny(copyAttr.getFieldName(), "200000173","200001735")){
                                copyAttr.setIsEdit(KeyConsts.IFTRUE_T);
                            }
                            else {
                                copyAttr.setIsEdit(KeyConsts.IFTRUE_F);
                            }

                        }
                        feeOfferInst.setAttr(copyAttr);
                    }
                }
                operateInstAttrService.setListAttrValue(feeOfferInst, feeOfferInst.listAttrs(), sceneInstId, null);
                feeOfferInst.setActionType(ActionType.K);
                feeOfferInst.setExtOfferInstId(fee.getDestItemId());
                operateSceneInstService.addAdditionalOfferInst(sceneInstId, feeOfferInst);
                operateChangeService.setDeleteInstChange(sceneInst, feeOfferInst, false, null, "");

                if (KiteStringUtils.isNotEmpty(changeType)) {
                    // 还原他的动作
                    if (KiteStringUtils.equals(ChangeTypeUtils.CHANGE_TYPE_D, changeType)) {
                        String startDate = feeOfferInst.getAttr("200000172").getValue();
                        // 未生效的资费，可以作废
                        if (KiteStringUtils.isNotEmpty(startDate)
                            && DateFormatUtils.compareDate(DateFormatUtils.getFormatedDateTime(), startDate, DateFormatUtils.DATE_TIME_FORMAT)<0) {
                            feeOfferInst.setActionType(ActionType.C);
                            feeOfferInst.setOriginalActionType(ActionType.K);
                            feeOfferInst.setExtOfferInstId(fee.getDestItemId());
                            operateSceneInstService.addAdditionalOfferInst(sceneInstId, feeOfferInst);
                        }
                        else {
                            String offerType = ProdFeeCache.get(feeOfferInst.getOfferId()).getOfferType();
                            // 还原销售品实例动作
                            operateSceneOfferInstService.removeOffer(sceneInstId, custId, feeOfferInst.getOfferInstId(), offerType);
                        }
                    }
                    else {
                        if(KiteStringUtils.isEqual(changeType, ChangeTypeUtils.CHANGE_TYPE_A)) {
                            // 追单，记录初始化的 instId，用于校验追单是否有业务信息变更校验（changeType都是A，无法判断是否是新增）
                            String bizType = querySceneInstService.getExtParameterValue(sceneInstId, "bizType");
                            if(KiteStringUtils.isEqual(sceneInst.getServiceOfferId(), LocalServiceOfferConsts.SERVICE_OFFER_FOLLOW) && "1001".equals(bizType)) {
                                String offerFollowInstIds = querySceneInstService.getExtParameterValue(sceneInstId, "offerFollowInstIds");
                                offerFollowInstIds = KiteStringUtils.isEmpty(offerFollowInstIds) ? feeOfferInst.getInstId() : (offerFollowInstIds + SymbolConsts.COMMA + feeOfferInst.getInstId());

                                operateSceneInstService.putExtParameter(sceneInstId, "offerFollowInstIds", offerFollowInstIds);
                            }
                        }

                        feeOfferInst.setActionType(ChangeTypeUtils.getActionType(changeType));
                        feeOfferInst.setOriginalActionType(feeOfferInst.getActionType());
                        operateSceneInstService.addAdditionalOfferInst(sceneInstId, feeOfferInst);
                    }
                }

                // 记录初始化信息，再选择资费变更修改后，再取消，需要还原资费信息
                Map<String, String> initFeeOfferActionMap = (Map<String, String>) Optional.ofNullable(querySceneInstService.getExtParameterValue(sceneInstId, "initFeeOfferActionMap")).orElse(new HashMap<>());
                initFeeOfferActionMap.put(feeOfferInst.getInstId(), ChangeTypeUtils.getChangeType(feeOfferInst.getActionType().name()));
                operateSceneInstService.putExtParameter(sceneInstId, "initFeeOfferActionMap", initFeeOfferActionMap);

            }
            operateSceneInstService.putExtParameter(sceneInstId, "feeInstIdMap_".concat(Optional.ofNullable(goods.getInstanceId()).orElse("")), feeInstIdMap);
        }
    }

    /**
     *
     * @param goodsSku 主产品sku
     * @param fees  需要初始化并还原到场景的资费集合
     */
    private void refreshAdditionalOfferCacheIfNesscessary(String goodsSku, List<KitePosGoodsFeeDTO> fees, String provinceNbr) {
        for (KitePosGoodsFeeDTO fee : fees) {
            Offer additionalOffer = ProdFeeCache.get(fee.getCode());
            List<OfferAttr> additionalOfferAttrs = ProdFeeAttrCache.get(fee.getCode(), goodsSku, provinceNbr);
            if (Objects.isNull(additionalOffer) || Objects.isNull(additionalOfferAttrs) || additionalOfferAttrs.isEmpty()) {
                SpringUtil.getBean(ILocalRefreshCacheService.class).refreshAdditionalOfferCache(goodsSku);
                break;
            }
        }
    }

    @SuppressWarnings("deprecation")
    private DataResult<String> addAdditionalOffer(String sceneInstId, String custId, String prodInstId, String offerId, String offerInstId, String type, boolean addOnly, LoginInfo loginInfo) {
        String staffId = loginInfo.getUserInfo().getUserId() + "";

        //checkOfferStatus(offerId);

        //特殊处理,规则设置触发条件 START -- 还原场景无需触发规则，订购时已经触发
        //operateSceneInstService.putExtParameter(sceneInstId, KeyConsts.KEY_DISABLE_RULE_ADDITIONAL_OFFER, KeyConsts.IFTRUE_F);

        OfferInstDTO offerInstDTO = null;
        //产品约束的可选包
        if (KeyConsts.ADDITIONAL_PRODUCT_TYPE.equals(type)) {
            if (addOnly) {
                offerInstDTO = operateSceneAdditionalOfferInstService
                    .addAdditionalOfferOfProduct(sceneInstId, prodInstId, offerId, custId, staffId, true).getResultObject();
            } else {
                offerInstDTO = operateSceneAdditionalOfferInstService
                    .addAdditionalOfferOfProduct(sceneInstId, prodInstId, offerId, custId, staffId).getResultObject();
            }

        } else if (KeyConsts.ADDITIONAL_OFFER_TYPE.equals(type)) {
            OfferInstDTO offerInst = querySceneMainOfferInstService.getSceneMainOfferInstByProdInstId(sceneInstId, prodInstId, custId).getResultObject();
            if (offerInst == null) {
                offerInst = querySceneCommonService
                    .getSceneOfferInstByOfferInstId(sceneInstId, offerInstId, custId).getResultObject();
            }
            offerInstId = offerInst.getOfferInstId();

            offerInstDTO = operateSceneAdditionalOfferInstService
                .addAdditionalOffer(sceneInstId, offerInstId, prodInstId, offerId, custId, staffId).getResultObject();
        }
        //特殊处理,规则设置触发条件 END; -- 还原场景无需触发规则，订购时已经触发
        //operateSceneInstService.putExtParameter(sceneInstId, KeyConsts.KEY_DISABLE_RULE_ADDITIONAL_OFFER, KeyConsts.IFTRUE_T);
        if (Objects.nonNull(offerInstDTO)) {
            return ErrorConsts.SUCCESS.getResult(offerInstDTO.getOfferInstId());
        }
        return null;
    }

    @Override
    @KiteTransactional
    public void initOfferInstAcct(String sceneInstId, String operType, String custId, KitePosDTO kitePosDTO, LoginInfo loginInfo) {
        StopWatch sw = new StopWatch("变更场景初始化-还原属性值-处理账户信息");
        sw.start("账户信息还原");
        List<KitePosGoodsDTO> goods = kitePosDTO.getGoods();
        if (KiteListUtils.isEmpty(goods)) {
            return;
        }
        if (KiteListUtils.isEmpty(kitePosDTO.getAccounts())) {
            return;
        }
        KiteSceneInst sceneInst = querySceneInstService.getSceneInst(sceneInstId);
        String serviceOfferId = sceneInst.getServiceOfferId();
        String sceneOperType = sceneInst.getOperType();
        if (Objects.equals(InstType.GIFT_OFFER_INST, sceneInst.getRootInstType())) {
            goods = goods.stream().filter(good -> GoodsHelper.isGift(good.getCode())).collect(Collectors.toList());
        }
        //FIXME 批量受理签订起租还原场景临时处理
        if (KiteStringUtils.equalsAny(querySceneInstService.getExtParameterValue(sceneInstId, "preTaskCode"),
            "batchSIGN", "batchOrderStartRent")) {
            goods = Lists.newArrayList(goods.stream().filter(good -> KiteListUtils.isNotEmpty(good.getPayRelation()))
                .findFirst().orElse(goods.get(0)));
        }
        goods.forEach((goodsDto) -> {
            List<KitePosGoodsPayRealtionDTO> payRelation = goodsDto.getPayRelation();
            if (!KiteListUtils.isEmpty(payRelation)) {
                payRelation.forEach((payRelationDto) -> {
                    KitePosAccountDTO acctDto = kitePosDTO.getAccounts().stream().filter(
                        (oo) -> KiteStringUtils.isNotEmpty(oo.getInstanceId()) && oo.getInstanceId()
                            .equals(payRelationDto.getAccountInstId())).findAny().orElse(null);
                    if (!KiteObjectUtils.isEmpty(acctDto)) {
                        CuccKiteOfferInstAcct acct = new CuccKiteOfferInstAcct();
                        //签订的用旧的，其它的用新的实例id
                       /* if (StringUtil.equals(LocalKeyConsts.SCENE_OPER_TYPE_ORDER_SIGN, operType)) {
                            acct.setInstId(acctDto.getInstanceId());
                        } else {
                            if (KiteStringUtils.isNotEmpty(acctDto.getInstanceId()) && !acctDto.getInstanceId().contains("_")) {
                                acct.setInstId(acctDto.getInstanceId());
                            } else {
                                acct.setInstId(IdUtils.generateInstId(InstType.PROD_INST_ACCT));
                            }
                        }*/
                       if(KiteStringUtils.isNotEmpty(acctDto.getInstanceId())){
                           // 为了防止合同、付费关系、折扣审批等信息实例id超长导致落购物车表失败，重新设置实例id（场景中有无此信息对定时任务不影响）
                           if (KiteStringUtils.equals(
                               querySceneInstService.getExtParameterValue(sceneInstId, "preTaskCode"),
                               "batchOrderStartRent")) {
                               acct.setInstId(IdUtils.generateInstId(InstType.PROD_INST_ACCT));
                           }
                           else {
                               acct.setInstId(acctDto.getInstanceId());
                           }
                       }else{
                           acct.setInstId(IdUtils.generateInstId(InstType.PROD_INST_ACCT));
                       }
                        if (!KiteStringUtils.equals(ServiceOfferConsts.SERVICE_OFFER_ORDER, serviceOfferId)) {
                            acct.setActionType(ChangeTypeUtils.getActionType(payRelationDto.getChangeType()));
                        } else {
                            acct.setActionType(ActionType.A);
                        }
                        acct.setAcctId(acctDto.getAccountId());
                        acct.setCustId(acctDto.getCustId());
                        acct.setCustName(acctDto.getCustName());
                        acct.setAcctName(acctDto.getName());
                        acct.setContractId(acctDto.getContractId());
                        acct.setProvinceCode(acctDto.getProvinceCode());
                        acct.setEparchyCode(acctDto.getEparchyCode());
                        acct.setAcctType(acctDto.getPayMode());
                        acct.setIsDefault(String.valueOf(payRelationDto.getIsDefault()));
                        acct.setExtInstId(acctDto.getDestItemId());
                        acct.setPayModeCode(acctDto.getPayMode());
                        acct.setInstType(InstType.OFFER_INST_ACCT);
                        // 调接口重新获取付费合同号和账户归属客户
                        // 2021-06-24改为异步处理com.iwhalecloud.bss.kite.cucc.service.scene.CuccSceneService.initAccountMoreInfo(String, String, String, String, String, String, Map<String, QryCustAccountReq>, KitePosDTO)
                        if (!GeneralSwitchUtils.isSwitchOpened("INIT_WITH_MUTIL_THREAD")) {
                            setAcctCustNameAndContractId(acct, acctDto, custId);
                        }
                        // 调接口重新获取是否总部直签客户
                        setIsCenterDirectSign(acct, acctDto, kitePosDTO.getUsers());
                        //从payRealtiaon获取PayitemCode
                        if (!KiteObjectUtils.isEmpty(payRelationDto)) {
                            acct.setAcctItemId(payRelationDto.getPayitemCode());
                            acct.setPayWay(payRelationDto.getPayWay());
                            acct.setPayLimit(payRelationDto.getPayLimit());
                            acct.setExtInstId(payRelationDto.getDestItemId());
                            acct.setStartDate(payRelationDto.getStartDate().substring(0, 4) + "-" + payRelationDto.getStartDate().substring(4, 6));
                            acct.setEndDate(payRelationDto.getEndDate().substring(0, 4) + "-" + payRelationDto.getEndDate().substring(4, 6));

                            if (!KiteStringUtils.isEmpty(payRelationDto.getAccountCycle())) {
                                acct.setAccountCycle(payRelationDto.getAccountCycle());
                            }
                            if (!KiteStringUtils.isEmpty(payRelationDto.getFeeCycle())) {
                                acct.setFeeCycle(payRelationDto.getFeeCycle());
                            }
                            // 如果是改类业务，需要将实例动作更改为K
                            if (!ServiceOfferConsts.SERVICE_OFFER_ORDER.equals(sceneInst.getServiceOfferId())) {
                                //acct.setOfferName(kitePosGoodsDTO.getName());
                                //acct.setOfferInstId(kitePosGoodsDTO.getCode());
                                String offerInstId = querySceneInstService.getSceneInst(sceneInstId).getRootInstId();
                                String offerName = querySceneInstService.getOfferInst(custId, offerInstId).getOfferName();
                                acct.setOfferName(offerName);
                                acct.setOfferInstId(offerInstId);
                                acct.setActionType(ActionType.K);
//                                acct.setIsDefault("1");
                            }
                        }
                        if (!Objects.isNull(goodsDto)) {
                            List<KiteOfferInst> offerInsts = this.querySceneInstService
                                .listMainOfferInsts(sceneInstId, goodsDto.getCode());
                            if (Objects.equals(InstType.GIFT_OFFER_INST, sceneInst.getRootInstType())) {
                                offerInsts = querySceneInstService.listGiftOfferInsts(sceneInstId)
                                    .stream().filter(giftInst -> goodsDto.getCode().equals(giftInst.getOfferId()))
                                    .collect(Collectors.toList());
                            }
                            if (KiteListUtils.isEmpty(offerInsts) && LocalKeyConsts.KITE_SCENE_INST_OPER_TYPE_1003.equals(sceneOperType)) {
                                // 核查转定商品变更场景，找同类型的产品-此方案不支持一个分类多个产品场景
                                OfferAttr cateIdAttr = OfferAttrCache.get(goodsDto.getCode()).stream().filter(attr -> "cateId".equals(attr.getFieldName())).findAny().get();
                                if (Objects.nonNull(cateIdAttr)) {
                                    String cateId = cateIdAttr.getDefaultValue();
                                    offerInsts = this.querySceneInstService.listMainOfferInsts(sceneInstId).stream().filter(offerInst3 -> {
                                        return KiteStringUtils.equals(cateId, offerInst3.getAttr("cateId").getDefaultValue());
                                    }).collect(Collectors.toList());
                                }
                            }
                            if (!KiteListUtils.isEmpty(offerInsts)) {
                                KiteOfferInst offerInst = offerInsts.get(0);
                                acct.setOfferInstId(offerInst.getOfferInstId());
                                acct.setOfferName(offerInst.getOfferName());
                            }
                        }
                        String changeType = payRelationDto.getChangeType();
                        if (KiteStringUtils.equals(ChangeTypeUtils.CHANGE_TYPE_A, changeType)) {
                            acct.setActionType(ActionType.A);
                        }
                        String offerInstAcctRelId = operateSceneInstService.addOfferInstAcct(sceneInstId, acct, acct.getOfferInstId(), RelType.OFFER_OBJ_REL_TYPE_170000, ActionType.A, KeyConsts.OFFER_ACCOUNT_ROLE, goodsDto.getCode());

                        if (KiteStringUtils.isNotEmpty(changeType) && KiteStringUtils.equals(ChangeTypeUtils.CHANGE_TYPE_D, changeType)) {
                            boolean f = operateSceneInstService.deleteOfferInstAcct(sceneInstId, offerInstAcctRelId);
                        }
                    }
                });
            }
        });
        sw.stop();
        LOGGER.info(sw.prettyPrint());
    }

    @Override
    @KiteTransactional
    public void initOfferInstContract(String sceneInstId, String operType, String custId, KitePosDTO kitePosDTO, LoginInfo loginInfo) {
        StopWatch sw = new StopWatch("变更场景初始化-还原属性值-处理合同信息");
        sw.start("合同信息还原");
        KiteSceneInst sceneInst = querySceneInstService.getSceneInst(sceneInstId);
        String serviceOfferId = sceneInst.getServiceOfferId();
        String sceneOperType = sceneInst.getOperType();
        List<KitePosContractDTO> contracts = kitePosDTO.getContract();
        if (KiteListUtils.isEmpty(contracts)) {
            return;
        }

        //FIXME 批量受理签订起租还原场景临时处理
        if (KiteStringUtils.equalsAny(querySceneInstService.getExtParameterValue(sceneInstId, "preTaskCode"),
            "batchSIGN", "batchOrderStartRent")) {
            contracts = Lists.newArrayList(contracts.get(0));
        }

        contracts.forEach((contract) -> {
            KiteOfferInstContract offerInstContractRel = new KiteOfferInstContract();
            //签订的用旧的，其它的用新的实例id
          /*  if (StringUtil.equals(LocalKeyConsts.SCENE_OPER_TYPE_ORDER_SIGN, operType)) {
                offerInstContractRel.setInstId(contract.getInstanceId());
            } else {
                // 注释原因，不管contract.getInstanceId()是否为空，都要走1780行，这样会导致生成多次
//                if (KiteStringUtils.isNotEmpty(contract.getInstanceId())) {
//                    offerInstContractRel.setInstId(contract.getInstanceId());
//                } else {
//                    offerInstContractRel.setInstId(IdUtils.generateInstId(InstType.PROD_INST_ACCT));
//
//                }
                offerInstContractRel.setInstId(IdUtils.generateInstId(InstType.PROD_INST_ACCT));

            }*/
            if(KiteStringUtils.isNotEmpty(contract.getInstanceId())){
                // 为了防止合同、付费关系、折扣审批等信息实例id超长导致落购物车表失败，重新设置实例id（场景中有无此信息对定时任务不影响）
                if (KiteStringUtils.equals(
                    querySceneInstService.getExtParameterValue(sceneInstId, "preTaskCode"),
                    "batchOrderStartRent")) {
                    offerInstContractRel.setInstId(IdUtils.generateInstId(InstType.PROD_INST_ACCT));
                }
                else {
                    offerInstContractRel.setInstId(contract.getInstanceId());
                }
            }else {
                offerInstContractRel.setInstId(IdUtils.generateInstId(InstType.PROD_INST_ACCT));
            }
            offerInstContractRel.setExtInstId(contract.getDestItemId());
            offerInstContractRel.setInstType(InstType.OFFER_INST_CONTRACT);
            //合同批次号
            offerInstContractRel.setContractBatchId(contract.getBatchCode());
            //合同编号
            offerInstContractRel.setContractNo(contract.getContractCode());
            offerInstContractRel.setContractName(contract.getName());
            offerInstContractRel.setInstType(InstType.OFFER_INST_CONTRACT);
            offerInstContractRel.setContractType(contract.getContractType());
            if (KiteStringUtils.isNotEmpty(contract.getStartTime())) {
                Date startTime = KiteDateUtils.parseStrToDate(contract.getStartTime(),KiteDateUtils.DATE_TIME_FORMAT_14);
                offerInstContractRel.setBeginDate(startTime);
            }
            if (KiteStringUtils.isNotEmpty(contract.getEndTime())) {
                Date endTime = KiteDateUtils.parseStrToDate(contract.getEndTime(),KiteDateUtils.DATE_TIME_FORMAT_14);
                offerInstContractRel.setEndDate(endTime);
            }
            if (!KiteStringUtils.equals(ServiceOfferConsts.SERVICE_OFFER_ORDER, serviceOfferId)) {
                offerInstContractRel.setActionType(ChangeTypeUtils.getActionType(contract.getChangeType()));
            } else {
                offerInstContractRel.setActionType(ActionType.A);
            }
            if (KiteListUtils.isNotEmpty(contract.getAttachments())) {
               /*  List<KitePosAttachmentDTO> attachments=contract.getAttachments();
               String url="";
                String name="";
                for(KitePosAttachmentDTO aht:attachments){
                    if(KiteStringUtils.isEmpty(url)){
                        url=KiteStringUtils.concatWithSymbol(url,aht.getUrl(),"");
                        name=KiteStringUtils.concatWithSymbol(name,aht.getName(),"");
                    }else{
                        url=KiteStringUtils.concatWithSymbol(url,aht.getUrl(),"|");
                        name=KiteStringUtils.concatWithSymbol(name,aht.getName(),"|");
                    }
                }
                offerInstContractRel.setContractUrl(url);
                offerInstContractRel.setAttachmentName(name);*/
                List<ContAttachmentDTO> attachment=new ArrayList<ContAttachmentDTO>();
                if(!KiteObjectUtils.isEmpty(contract.getAttachments())){
                    String oldattachment = JSONObject.toJSONString(contract.getAttachments());
                    attachment=JSONObject.parseArray(oldattachment, ContAttachmentDTO.class);
                    offerInstContractRel.setAttachments(attachment);
                }
            } /*else if (!GeneralSwitchUtils.isSwitchOpened("INIT_WITH_MUTIL_THREAD")){
                *//* 查询合同耗时长，改为放到异步线程中处理*//*
                String cateId = CuccPosServiceUtils.getCateId(sceneInstId, custId);
                List<CustContractRsp> contractInfoList = infServiceBus
                    .listContractInfo(kitePosDTO.getCustomer().getCustId(), contract.getContractCode(),
                        contract.getName(), null, loginInfo.getUserInfo().getPostProvinceNbr(), 1, 10,cateId);
                List<ContAttachmentDTO> attachment=new ArrayList<ContAttachmentDTO>();
                if(!KiteObjectUtils.isEmpty(contract.getAttachments())){
                    String oldattachment = JSONObject.toJSONString(contract.getAttachments());
                    attachment=JSONObject.parseArray(oldattachment, ContAttachmentDTO.class);
                    offerInstContractRel.setAttachments(attachment);
                }
              *//*  if (KiteListUtils.isNotEmpty(contractInfoList)) {
                    offerInstContractRel.setContractUrl(contractInfoList.get(0).getAccessoryId());
                    if (KiteListUtils.isNotEmpty(contractInfoList.get(0).getAccessoryInfo())) {
                        offerInstContractRel.setAttachmentName(contractInfoList.get(0).getAccessoryInfo().get(0).getOriginalName());
                    }
                }*//*
            }*/

            List<KitePosGoodsDTO> goods = kitePosDTO.getGoods().stream()
                .filter(oo -> {
                    String contractInstId = oo.getContractInstId();
                    if (KiteStringUtils.isEmpty(contractInstId)) {
                        return false;
                    }
                    if (StringUtil.equals(contractInstId, contract.getInstanceId())) {
                        return true;
                    }
                    if (contractInstId.startsWith("[")) {
                        try {
                            JSONArray contractInst = JSONObject.parseArray(contractInstId);
                            if (contractInst.contains(contract.getInstanceId())) {
                                return true;
                            }
                        }
                        catch (Exception e) {
                            return false;
                        }
                    }
                    return false;
                }).collect(Collectors.toList());

            if (Objects.equals(InstType.GIFT_OFFER_INST, sceneInst.getRootInstType())) {
                goods = goods.stream().filter(good -> GoodsHelper.isGift(good.getCode())).collect(Collectors.toList());
            }
            KitePosGoodsDTO goodsDto = goods.stream().findAny().orElse(null);
            if (!Objects.isNull(goodsDto)) {
                List<KiteOfferInst> offerInsts = this.querySceneInstService.listMainOfferInsts(sceneInstId, goodsDto.getCode());
                if (Objects.equals(InstType.GIFT_OFFER_INST, sceneInst.getRootInstType())) {
                    offerInsts = querySceneInstService.listGiftOfferInsts(sceneInstId)
                        .stream().filter(giftInst -> goodsDto.getCode().equals(giftInst.getOfferId()))
                        .collect(Collectors.toList());
                }
                if (KiteListUtils.isEmpty(offerInsts) && LocalKeyConsts.KITE_SCENE_INST_OPER_TYPE_1003.equals(sceneOperType)) {
                    // 核查转定商品变更场景，找同类型的产品-此方案不支持一个分类多个产品场景
                    OfferAttr cateIdAttr = OfferAttrCache.get(goodsDto.getCode()).stream().filter(attr -> "cateId".equals(attr.getFieldName())).findAny().get();
                    if (Objects.nonNull(cateIdAttr)) {
                        String cateId = cateIdAttr.getDefaultValue();
                        offerInsts = this.querySceneInstService.listMainOfferInsts(sceneInstId).stream().filter(offerInst4 -> {
                            return KiteStringUtils.equals(cateId, offerInst4.getAttr("cateId").getDefaultValue());
                        }).collect(Collectors.toList());
                    }
                }
                if (!KiteListUtils.isEmpty(offerInsts)) {
                    KiteOfferInst offerInst = offerInsts.get(0);
                    offerInstContractRel.setOfferInstId(offerInst.getOfferInstId());
                }

                String changeType = contract.getChangeType();
                if (KiteStringUtils.equals(ChangeTypeUtils.CHANGE_TYPE_A, changeType)) {
                    offerInstContractRel.setActionType(ActionType.A);
                }
                else if (KiteObjectUtils.isEmpty(offerInstContractRel.getActionType()) || KiteStringUtils
                    .isEmpty(offerInstContractRel.getActionType().name())) {
                    offerInstContractRel.setActionType(ActionType.K);
                }
                String offerObjInstRelId = operateSceneInstService.addOfferInstContract(sceneInstId, offerInstContractRel, offerInstContractRel.getOfferInstId(), RelType.OFFER_OBJ_REL_TYPE_190000, ActionType.K, KeyConsts.OFFER_CONTRACT_ROLE, goodsDto.getCode());
                if (KiteStringUtils.isNotEmpty(changeType) && KiteStringUtils.equals(ChangeTypeUtils.CHANGE_TYPE_D, changeType)) {
                    boolean f = operateSceneInstService.deleteOfferInstContract(sceneInstId, offerObjInstRelId);
                }
                if (ServiceOfferConsts.SERVICE_OFFER_TRANSFER.equals(serviceOfferId) && KiteStringUtils.isEmpty(changeType)) {
                    boolean f = operateSceneInstService.deleteOfferInstContract(sceneInstId, offerObjInstRelId);
                }
            }
        });
        sw.stop();
        LOGGER.info(sw.prettyPrint());
    }

    @Override
    @KiteTransactional
    public void initOfferInstDiscount(String sceneInstId, String operType, String custId, KitePosDTO kitePosDTO, LoginInfo loginInfo) {
        KiteSceneInst sceneInst = querySceneInstService.getSceneInst(sceneInstId);
        String serviceOfferId = sceneInst.getServiceOfferId();
        String sceneOperType = sceneInst.getOperType();
        List<KitePosDiscountDTO> discounts = kitePosDTO.getDiscount();
        if (KiteListUtils.isNotEmpty(discounts)) {
            //FIXME 批量受理签订起租还原场景临时处理
            if (KiteStringUtils.equalsAny(querySceneInstService.getExtParameterValue(sceneInstId, "preTaskCode"),
                "batchSIGN", "batchOrderStartRent")) {
                discounts = Lists.newArrayList(discounts.get(0));
            }
            List<KitePosDiscountDTO> finalDiscounts = discounts;
            discounts.forEach((discountDto) -> {
                KiteOfferInstDiscount discount = new KiteOfferInstDiscount();
                if(KiteStringUtils.isNotEmpty(discountDto.getInstanceId())){
                    // 为了防止合同、付费关系、折扣审批等信息实例id超长导致落购物车表失败，重新设置实例id（场景中有无此信息对定时任务不影响）
                    if (KiteStringUtils.equals(
                        querySceneInstService.getExtParameterValue(sceneInstId, "preTaskCode"),
                        "batchOrderStartRent")) {
                        discount.setInstId(IdUtils.generateInstId(InstType.PROD_INST_ACCT));
                    }
                    else {
                        discount.setInstId(discountDto.getInstanceId());
                    }
                }else {
                    discount.setInstId(SeqUtils.getNext("SEQ_DISCOUNT_INST_ID"));
                }
                discount.setExtInstId(discountDto.getDestItemId());
                discount.setDiscountName(discountDto.getName());
                discount.setDiscountOrderId(discountDto.getDestItemId());
                discount.setDiscountType(discountDto.getType());
                List<KitePosAttachmentDTO> attachments = finalDiscounts.get(0).getAttachments();
                if (KiteListUtils.isNotEmpty(attachments)) {
                    if(KiteStringUtils.isEmpty(discountDto.getType())){
                        discount.setDiscountType("ATTACHMENTS_TYPE_" + attachments.get(0).getCatagory());
                    }
                    if (KiteStringUtils.contains(discountDto.getAttachments().get(0).getUrl(), ".") && KiteStringUtils
                        .isNotBlank(discountDto.getName())) {
                        discount.setDiscountFileUrl(
                            discountDto.getAttachments().get(0).getUrl() + "*_*" + discountDto.getName() + discountDto
                                .getAttachments().get(0).getUrl()
                                .substring(discountDto.getAttachments().get(0).getUrl().lastIndexOf(".")));
                    }
                    else {
                        discount.setDiscountFileUrl(discountDto.getAttachments().get(0).getUrl());
                    }
                }
//                discount.setDiscountType(discountDto.getType());
                discount.setInstType(InstType.OFFER_INST_DISCOUNT);
                if (!KiteStringUtils.equals(ServiceOfferConsts.SERVICE_OFFER_ORDER, serviceOfferId)) {
                    discount.setActionType(ChangeTypeUtils.getActionType(discountDto.getChangeType()));
                } else {
                    discount.setActionType(ActionType.A);
                }

                List<KitePosGoodsDTO> goods = kitePosDTO.getGoods().stream()
                    .filter((oo) -> KiteStringUtils.isEqual(oo.getDiscountInstId(), discountDto.getInstanceId())).collect(Collectors.toList());
                if (Objects.equals(InstType.GIFT_OFFER_INST, sceneInst.getRootInstType())) {
                    goods = goods.stream().filter(good -> GoodsHelper.isGift(good.getCode())).collect(Collectors.toList());
                }
                KitePosGoodsDTO goodsDto = goods.stream().findAny().orElse(null);
                if (!Objects.isNull(goodsDto)) {
                    List<KiteOfferInst> offerInsts = this.querySceneInstService.listMainOfferInsts(sceneInstId, goodsDto.getCode());
                    if (Objects.equals(InstType.GIFT_OFFER_INST, sceneInst.getRootInstType())) {
                        offerInsts = querySceneInstService.listGiftOfferInsts(sceneInstId)
                            .stream().filter(giftInst -> goodsDto.getCode().equals(giftInst.getOfferId()))
                            .collect(Collectors.toList());
                    }
                    if (KiteListUtils.isEmpty(offerInsts) && LocalKeyConsts.KITE_SCENE_INST_OPER_TYPE_1003.equals(sceneOperType)) {
                        // 核查转定商品变更场景，找同类型的产品-此方案不支持一个分类多个产品场景
                        OfferAttr cateIdAttr = OfferAttrCache.get(goodsDto.getCode()).stream().filter(attr -> "cateId".equals(attr.getFieldName())).findAny().get();
                        if (Objects.nonNull(cateIdAttr)) {
                            String cateId = cateIdAttr.getDefaultValue();
                            offerInsts = this.querySceneInstService.listMainOfferInsts(sceneInstId).stream().filter(offerInst5 -> {
                                return KiteStringUtils.equals(cateId, offerInst5.getAttr("cateId").getDefaultValue());
                            }).collect(Collectors.toList());
                        }
                    }
                    if (!KiteListUtils.isEmpty(offerInsts)) {
                        KiteOfferInst offerInst = offerInsts.get(0);
                        discount.setOfferInstId(offerInst.getOfferInstId());
                        discount.setOfferName(offerInst.getOfferName());
                    }
                    this.operateSceneInstService.addOfferInstDiscount(sceneInstId, discount, discount.getOfferInstId(), RelType.OFFER_OBJ_REL_TYPE_180000, ActionType.K, KeyConsts.OFFER_DISCOUNT_ROLE, goodsDto.getCode());

                }
            });
        }
    }

    @Override
    @KiteTransactional
    public void initOfferInstDelivery(String sceneInstId, String operType, String custId, KitePosDTO kitePosDTO, LoginInfo loginInfo) {
        List<KitePosDeliveryDTO> deliverys = kitePosDTO.getDelivery();
        if (!KiteListUtils.isEmpty(deliverys)) {
            List<Map<String, Object>> deliveryInfos = Lists.newArrayList();
            List<Map<String, Object>> delDeliveryInfos = Lists.newArrayList();
            deliverys.forEach(delivery -> {
                Map<String, Object> restMap = new HashMap<>();

                List<KiteAttr> kiteAttrs = querySceneInstService.listCommonAttrsByModuleId(sceneInstId, LocalKeyConsts.DELIVERYINFO_MODULEID)
                    .stream().filter(kiteAttr -> !KiteStringUtils.isEqual("H", kiteAttr.getShowType()) && !KiteStringUtils.isEqual("1", kiteAttr.getObjId()))
                    .collect(Collectors.toList());

                List<KitePosGoodsDTO> targetGoods = kitePosDTO.getGoods().stream().filter(goods -> KiteStringUtils.equals(goods.getDeliveryInstId(), delivery.getInstanceId())).collect(Collectors.toList());
                if (!KiteListUtils.isEmpty(targetGoods)) {
                    List<KiteAttr> offerNameAttrs = kiteAttrs.stream()
                        .filter(attr -> KiteStringUtils.equals(attr.getFieldName(), "offerName"))
                        .collect(Collectors.toList());
                    String offerId = targetGoods.get(0).getCode();
                    List<KiteOfferInst> offerInsts = querySceneInstService.listMainOfferInsts(sceneInstId, offerId);
                    if (KiteListUtils.isEmpty(offerInsts)) {
                        offerInsts.add(querySceneInstService.getGiftOfferInst(sceneInstId, offerId));
                    }
                    if (!KiteListUtils.isEmpty(offerInsts) && !KiteListUtils.isEmpty(offerNameAttrs)) {
                        KiteOfferInst offerInst = offerInsts.get(0);
                        KiteAttr attr = offerNameAttrs.get(0);
                        attr.setValue(offerInst.getOfferInstId());
                        attr.setValueDesc(offerInst.getOfferName());
                        restMap.put("offerInstId", offerInst.getOfferInstId());
                    }
                }
                if (KiteStringUtils.isNotEmpty(delivery.getChangeType())) {
                    restMap.put("actionType", ChangeTypeUtils.getActionType(delivery.getChangeType()));
                } else {
                    restMap.put("actionType", ActionType.A.name());
                }
                List<KiteAttr> remarkAttrs = kiteAttrs.stream().filter(attr -> KiteStringUtils.equals(attr.getFieldName(), "ORD10041")).collect(Collectors.toList()); //备注
                if (!KiteListUtils.isEmpty(remarkAttrs)) {
                    KiteAttr attr = remarkAttrs.get(0);
                    attr.setValue(delivery.getRemark());
                    attr.setValueDesc(delivery.getRemark());
                }
                List<KiteAttr> accNumAttrs = kiteAttrs.stream().filter(attr -> KiteStringUtils.equals(attr.getFieldName(), "accNum")).collect(Collectors.toList());
                if (!KiteListUtils.isEmpty(accNumAttrs)) {
                    KiteAttr attr = accNumAttrs.get(0);
                    KiteAttr businessNumber = querySceneInstService.getCommonAttr(sceneInstId, "business_number");
                    attr.setValue(businessNumber.getValue());
                    attr.setValueDesc(businessNumber.getValue());
                }
                List<KiteAttr> ORD10037Attrs = kiteAttrs.stream().filter(attr -> KiteStringUtils.equals(attr.getFieldName(), "ORD10037")).collect(Collectors.toList()); //收货人
                if (!KiteListUtils.isEmpty(ORD10037Attrs)) {
                    KiteAttr attr = ORD10037Attrs.get(0);
                    attr.setValue(delivery.getName());
                    attr.setValueDesc(delivery.getName());
                }
                List<KiteAttr> ORD10038Attrs = kiteAttrs.stream().filter(attr -> KiteStringUtils.equals(attr.getFieldName(), "ORD10038")).collect(Collectors.toList()); //收货人电话
                if (!KiteListUtils.isEmpty(ORD10038Attrs)) {
                    KiteAttr attr = ORD10038Attrs.get(0);
                    attr.setValue(delivery.getPhone());
                    attr.setValueDesc(delivery.getPhone());
                }
                List<KiteAttr> ORD10039Attrs = kiteAttrs.stream().filter(attr -> KiteStringUtils.equals(attr.getFieldName(), "ORD10039")).collect(Collectors.toList()); //收货人身份证
                if (!KiteListUtils.isEmpty(ORD10039Attrs)) {
                    KiteAttr attr = ORD10039Attrs.get(0);
                    attr.setValue(delivery.getIdNo());
                    attr.setValueDesc(delivery.getIdNo());
                }
                List<KiteProdInst> kiteProdInsts = querySceneInstService.listProdInsts(sceneInstId);
                if (KiteListUtils.isEmpty(kiteProdInsts)) {
                    return;
                }
                List<KiteAttr> ORD10053Attrs = kiteAttrs.stream().filter(attr -> KiteStringUtils.equals(attr.getFieldName(), "ORD10053")).collect(Collectors.toList()); //省份
                if (!KiteListUtils.isEmpty(ORD10053Attrs)) {
                    KiteAttr attr = ORD10053Attrs.get(0);
                    attr.setValue(delivery.getProvince());
                    String provinceDesc = Optional.ofNullable(
                            LocalAttrHelper.getPlatformRegionName("", attr.getValue(), "10",kiteProdInsts.get(0).getProdId())).orElse("");
                    attr.setValueDesc(provinceDesc);
                }
                List<KiteAttr> ORD10054Attrs = kiteAttrs.stream().filter(attr -> KiteStringUtils.equals(attr.getFieldName(), "ORD10054")).collect(Collectors.toList()); //地市
                if (!KiteListUtils.isEmpty(ORD10054Attrs)) {
                    KiteAttr attr = ORD10054Attrs.get(0);
                    attr.setValue(delivery.getCity());
                    String cityDesc = Optional.ofNullable(
                        LocalAttrHelper.getPlatformRegionName("", attr.getValue(), "20", kiteProdInsts.get(0).getProdId())).orElse("");
                    attr.setValueDesc(cityDesc);
                }
                List<KiteAttr> ORD10055Attrs = kiteAttrs.stream().filter(attr -> KiteStringUtils.equals(attr.getFieldName(), "ORD10055")).collect(Collectors.toList()); //区县
                if (!KiteListUtils.isEmpty(ORD10055Attrs)) {
                    KiteAttr attr = ORD10055Attrs.get(0);
                    attr.setValue(delivery.getDistrict());
                    String countyDesc = Optional.ofNullable(
                        LocalAttrHelper.getPlatformRegionName("", attr.getValue(), "30", kiteProdInsts.get(0).getProdId())).orElse("");
                    attr.setValueDesc(countyDesc);
                }
                List<KiteAttr> ORD10040Attrs = kiteAttrs.stream().filter(attr -> KiteStringUtils.equals(attr.getFieldName(), "ORD10040")).collect(Collectors.toList()); //详细地址
                if (!KiteListUtils.isEmpty(ORD10040Attrs)) {
                    KiteAttr attr = ORD10040Attrs.get(0);
                    attr.setValue(delivery.getAddress());
                    attr.setValueDesc(delivery.getAddress());
                }

                // 这里需要替换成查回来的instanceId，否则订单修改时，对端判断instanceId不同会新增一条
                restMap.put("instId", delivery.getInstanceId());
//                restMap.put("instId", SeqUtils.getNext("SEQ_OFFER_INST_DELIVERY_REL_ID"));
                restMap.put("sceneInstId", sceneInstId);
                //restMap.put("offerInstId",offerInstId);
                restMap.put("extInstId", delivery.getDestItemId());
                restMap.put("kiteAttrs", kiteAttrs);
                restMap.put("isSync", true);
                if (KiteStringUtils.equals(String.valueOf(restMap.get("actionType")), ActionType.D.name())) {
                    delDeliveryInfos.add(restMap);
                }
                else {
                    deliveryInfos.add(restMap);
                }

            });

            operateSceneInstService.putExtParameter(sceneInstId, "offerInstDeliveryInfos", deliveryInfos);
            operateSceneInstService.putExtParameter(sceneInstId, "offerInstDeliveryInfosDel", delDeliveryInfos);
        }

    }

    private void afterProdAttrExecute(String sceneInstId, String custId) {
        // 回填资费计划中的折扣率按原值展示,不展示重新计算的值
        this.specialProcessForDiscountRateAttrValue(sceneInstId);
    }

    public void setAcctCustNameAndContractId(CuccKiteOfferInstAcct acct, KitePosAccountDTO acctDto, String custId) {
        if (KiteStringUtils.isEmpty(acctDto.getCustName()) || KiteStringUtils.isEmpty(acctDto.getContractId())
            ||KiteStringUtils.isEmpty(acct.getCbssAccountCode())) {
            PageInfo<QryCustAccountReq> qryAccount = localAccountService.listCustAccountInfo("", "",
                acctDto.getPayMode(), acctDto.getAccountId(), "", "", "", acctDto.getProvinceCode(),
                acctDto.getEparchyCode(), null,1, 10);
            if (Objects.nonNull(qryAccount) && KiteListUtils.isNotEmpty(qryAccount.getList())) {
                QryCustAccountReq accountReq = qryAccount.getList().get(0);
                //acct.setCustName(accountReq.getCustAccount().getCustName());
                //acct.setContractId(accountReq.getCustAccount().getContractId());
                acct.setCbssAccountCode(accountReq.getCustAccount().getCbssAccountCode());
                // 开户时间
                if (KiteStringUtils.isEmpty(acct.getOpenDateFormat()) && Objects
                    .nonNull(accountReq.getCustAccount().getOpenDate())) {
                    Long time = accountReq.getCustAccount().getOpenDate().getTime();
                    acct.setOpenDateFormat(DateUtils.formatTime(time));
                }

                acct.setCbssAccountCode(accountReq.getCustAccount().getCbssAccountCode());
                acct.setAccountCycle(accountReq.getCustAccount().getAccountCycle());
                acct.setFeeCycle(accountReq.getCustAccount().getPayCycle());
                acct.setAcctName(accountReq.getCustAccount().getPayName());
                acct.setIsCenterDirectSign(accountReq.getCustAccount().getIsCenterDirectSign());
                //acct.setStartDate(accountReq.getStartDate());
                //acct.setEndDate(accountReq.getEndDate());
                // 开户时间
                /*if (Objects.nonNull(accountReq.getCustAccount().getOpenDate())) {
                    Long time = accountReq.getCustAccount().getOpenDate().getTime();
                    acct.setOpenDate(DateUtils.formatTime(time));
                }
                if (KiteStringUtils.isNotEmpty(accountReq.getCustAccount().getContractId())) {
                    acct.setContractId(accountReq.getCustAccount().getContractId());
                }
            }
            // 客户账户查询接口有时候查不回数据，兼容下取二次业务接口返回的账户归属客户名称以及付费合同号
            /*if (KiteStringUtils.isEmpty(acct.getCustName()) && KiteStringUtils.isNotEmpty(acctDto.getCustName())) {
                acct.setCustName(acctDto.getCustName());
            }
            if (KiteStringUtils.isEmpty(acct.getContractId()) && KiteStringUtils.isNotEmpty(acctDto.getContractId())) {
                acct.setContractId(acctDto.getContractId());
            }*/
            }
        }
        /*else {
            acct.setCustName(acctDto.getCustName());
            acct.setContractId(acctDto.getContractId());
        }*/
    }

    private void setIsCenterDirectSign(CuccKiteOfferInstAcct acct, KitePosAccountDTO acctDto, List<KitePosUserDTO> users) {
        if (KiteStringUtils.isEmpty(acctDto.getIsCenterDirectSign())) {
            // 如果是否总部收费属性为是，则必为总部收费账户
            if (KiteListUtils.isNotEmpty(users)) {
                users.forEach(user -> {
                    if(Objects.nonNull(user.getAttrs())){
                        KitePosAttrDTO userAttr = user.getAttrs().stream().filter(attr -> (KiteStringUtils.equals(LocalKeyConsts.IS_LEADER_CHARGE, attr.getCode()) || KiteStringUtils
                            .equals(LocalKeyConsts.IS_LEADER_CHARGE_NEW, attr.getCode()))).findFirst().orElse(null);
                        if (Objects.nonNull(userAttr) && ("1".equals(userAttr.getValue()) || "1_0000106".equals(userAttr.getValue()))) {
                            acct.setIsCenterDirectSign("1");
                        }
                    }
                });
            }
        } else {
            acct.setIsCenterDirectSign(acctDto.getIsCenterDirectSign());
        }
    }

    private void dealProdInstAttrsforBussChange(String sceneInstId, KiteProdInst prodInst, String custId) {
        String serviceOfferId = this.querySceneInstService.getSceneInst(sceneInstId).getServiceOfferId();
      //如果是业务变更,按service_control_scope的配置处理是否可编辑
       CuccOperateInstAttrService cuccOperateInstAttrService = SpringUtil.getBean(CuccOperateInstAttrService.class);
       ProdAttrModuleVO prodAttrModuleVO = cuccOperateInstAttrService
           .processAttrs(sceneInstId, custId, prodInst.getProdInstId(),serviceOfferId, prodInst.getProdId());
       if (KiteListUtils.isEmpty(prodAttrModuleVO.getProdAttrList())) {
           return;
       }
       Map<String, String> fieldNameAndIsEdit = prodAttrModuleVO.getProdAttrList().stream().collect(
           Collectors.toMap(ProdAttrVO::getFieldName,
               prodAttrVO -> Optional.ofNullable(prodAttrVO.getIsEdit()).orElse("T"), (v1, v2) -> v1));

       List<KiteAttr> prodAttrs = querySceneInstService.listProdInstAttrs(custId, prodInst.getProdInstId());
       if (KiteListUtils.isEmpty(prodAttrs)) {
           return;
       }
       for (KiteAttr attr : prodAttrs) {
           String fieldName = attr.getFieldName();
           if ( KiteStringUtils.isNotEmpty(fieldNameAndIsEdit.get(fieldName))
               && KiteStringUtils.isEqual(fieldNameAndIsEdit.get(fieldName), KeyConsts.IFTRUE_T)) {
               attr.setIsEdit(KeyConsts.IFTRUE_T);
           }
           else {
               attr.setIsEdit(KeyConsts.IFTRUE_F);
           }
       }
       operateSceneInstService.setProdInstAttrs(sceneInstId, prodInst.getProdInstId(), prodAttrs);
    }

 // 处理一对多属性信息还原场景
    private void dealProdSpecAttr(String sceneInstId, KiteProdInst prodInst, List<KitePosAttrDTO> prodInstAttrs, LoginInfo loginInfo) {
        List<KiteAttr> attrs = KiteListUtils.isNotEmpty(prodInst.listAttrs()) ? prodInst.listAttrs() : new ArrayList<>();
        if (KiteListUtils.isEmpty(attrs)) {
            return;
        }

        String cateId = Optional.ofNullable(ProductCache.get(prodInst.getProdId())).map(Product::getCateId).orElse("");
        List<DcPublic> list = DcPublicCache.get("20210719001");
        KiteSceneInst kiteSceneInst = querySceneInstService.getSceneInst(sceneInstId);
        KiteInst kiteInst = querySceneInstService.getKiteInst(kiteSceneInst.getCustId(), kiteSceneInst.getRootInstType(), kiteSceneInst.getRootInstId());
        // 是否五大双线落地方产品
        boolean flag = (list != null) && list.stream().anyMatch(dcPublic -> KiteStringUtils.isEqual(kiteInst.getSpecId(), dcPublic.getCodeb()));
        if(flag) {
            // 五大双线落地方产品-发起方地市 200002058
            KiteAttr kiteAttr = attrs.stream().filter(attr -> KiteStringUtils.isEqual(attr.getFieldName(), "200002058")).findFirst().orElse(null);
            if (Objects.nonNull(kiteAttr) && StrTools.isContainChinese(kiteAttr.getValue())) {
                String attrValue = kiteAttr.getValue();
                String regionCode = LocalAttrHelper.getCityNameFromRegionName(attrValue, prodInst.getProdId());
                if(KiteStringUtils.isEmpty(regionCode)) {
                    regionCode = attrValue;
                }
                operateInstAttrService.setAttrValue(prodInst, kiteAttr.getFieldName(), regionCode, sceneInstId, CommonUtil.getAttrDataJson(TriggerStrategy.LOAD_VALUE));
                prodInst.setAttr(kiteAttr);
            }
        } else {
            // 装机地址的省市区属性还原
            String prodServiceId = prodInst.getRoleId();
            List<DcPublic> dcPublicList = DcPublicCache.getByPkey("20210318001", prodServiceId);
            if (KiteListUtils.isNotEmpty(dcPublicList)) {
                dcPublicList.forEach(dcPublic ->{
                    if (KiteStringUtils.isNotEmpty(dcPublic.getPcode()) && KiteStringUtils.isNotEmpty(dcPublic.getCodea())) {
                        // 上海云专线不需要拼装2_0000209属性
                        if (KiteStringUtils.equals(cateId, "2100971") && KiteStringUtils.equals(dcPublic.getPcode(), "2_0000209")) {
                            return;
                        }
                        KiteAttr prodAttr = attrs.stream().filter(attr3 -> KiteStringUtils.isEqual(attr3.getFieldName(), dcPublic.getPcode())).findFirst().orElse(null);
                        if (Objects.nonNull(prodAttr)) {
                            List<String> attrValue = Arrays.stream(dcPublic.getCodea().split(SymbolConsts.COMMA)).map(s -> {
                                KitePosAttrDTO prodInstAttr = prodInstAttrs.stream().filter(instAttr -> KiteStringUtils.isEqual(s, instAttr.getCode())).findFirst().orElse(null);
                                return Objects.nonNull(prodInstAttr) ? prodInstAttr.getValue() : "";
                            }).collect(Collectors.toList());
                            List<String> attrOriginValue = Arrays.stream(dcPublic.getCodea().split(SymbolConsts.COMMA)).map(s -> {
                                KitePosAttrDTO prodInstAttr = prodInstAttrs.stream().filter(instAttr -> KiteStringUtils.isEqual(s, instAttr.getCode())).findFirst().orElse(null);
                                String originValue = Objects.nonNull(prodInstAttr) ? prodInstAttr.getOriginValue() : "";
                                return Optional.ofNullable(originValue).orElse(Objects.nonNull(prodInstAttr) ? prodInstAttr.getValue() : "");
                            }).collect(Collectors.toList());
                            prodAttr.setOriginValue(KiteStringUtils.join(attrOriginValue, SymbolConsts.COMMA));
                            prodAttr.setOldValue(KiteStringUtils.join(attrValue, SymbolConsts.COMMA));
                            operateInstAttrService.setAttrValue(prodInst, prodAttr.getFieldName(), KiteStringUtils.join(attrValue, SymbolConsts.COMMA), sceneInstId, CommonUtil.getAttrDataJson(TriggerStrategy.LOAD_VALUE));

                            prodInst.setAttr(prodAttr);
                        }
                    }
                });
            }
        }

        // SDWAN订单签订、重提，若订单来源系统是外平台，则设置部分属性不可修改，并将属性改为非必填
        Map<String, Object> extParams = loginInfo.getUserInfo().getExtParams();
        String taskCode = KiteMapUtils.getString(extParams, "nodeCode");

        if(KiteStringUtils.equalsAny(taskCode, "OrderSigned", "OrderResubmit")) {
            DcPublic dcPublic = DcPublicCache.get("2021062501", cateId);
            if (dcPublic != null) {
                String orderSource = KiteMapUtils.getString(extParams, "orderSource");

                String codeA = dcPublic.getCodea();
                String codeB = dcPublic.getCodeb();
                if(KiteStringUtils.isNotEmpty(codeA) && KiteStringUtils.isNotEmpty(codeB)
                    && !KiteStringUtils.equalsAny(orderSource, codeB.split(SymbolConsts.COMMA))) {

                    String[] sdwanAttrArr = codeA.split(SymbolConsts.COMMA);
                    attrs.forEach(kiteAttr -> {
                        if(KiteStringUtils.equalsAny(kiteAttr.getFieldName(), sdwanAttrArr)) {
                            kiteAttr.setIsEdit(KeyConsts.IFTRUE_F);
                            kiteAttr.setIsNull(KeyConsts.IFTRUE_T);
                        }
                    });
                }
            }
        }
    }

    @Override
    @KiteTransactional
    public void initSerialNumbers(String sceneInstId, String operType, String custId, KitePosDTO kitePosDTO, LoginInfo loginInfo) {
        InstType instType = this.querySceneInstService.getSceneInst(sceneInstId).getRootInstType();
        String serviceOfferId = this.querySceneInstService.getSceneInst(sceneInstId).getServiceOfferId();
        // 追加订购、订购不需还原成员商品的号码
        if (!Objects.equals(InstType.GIFT_OFFER_INST, instType) || KiteStringUtils
            .equals(ServiceOfferConsts.SERVICE_OFFER_ORDER, serviceOfferId)) {
            return;
        }
        List<KitePosGoodsDTO> goodsList = kitePosDTO.getGoods();
        if (KiteListUtils.isEmpty(goodsList)) {
            return;
        }
        //FIXME 批量受理签订起租还原场景临时处理
        if (KiteStringUtils.equalsAny(querySceneInstService.getExtParameterValue(sceneInstId, "preTaskCode"),
            "batchSIGN", "batchOrderStartRent")) {
            goodsList = Lists.newArrayList(goodsList.get(0));
        }
        goodsList.forEach(goods -> {
            List<KitePosProductDTO> products = goods.getProducts();
            for (KitePosProductDTO posProdDto : products) {
                List<KitePosUserDTO> users = kitePosDTO.getUsers().stream().filter(user -> KiteStringUtils.equals(user.getInstanceId(), goods.getUserInstId())).collect(Collectors.toList());
                if (!KiteListUtils.isEmpty(users)) {
                    List<KiteProdInst> prodInsts = this.querySceneInstService.listProdInstsByProdId(sceneInstId, posProdDto.getCode());

                    Iterator<KiteProdInst> it = prodInsts.iterator();
                    while (it.hasNext()) {
                        KiteProdInst prodInst = it.next();
                        KiteAttr kiteAttr = prodInst.getAttr("200002981");
                        if (!KiteObjectUtils.isEmpty(kiteAttr)) {
                            operateInstAttrService.setAttrValue(prodInst, kiteAttr.getFieldName(), users.get(0).getSerialNumber(), sceneInstId, null);
                            users.remove(0);
                            it.remove();
                        }
                    }
                }
            }
        });
    }


    /**
     * 获取map中第一个数据值，并从map删掉
     *
     * @param map 数据源
     * @return key 属性组实例ID
     * @return value 属性组的属性列表
     */
    private Map<String, Object> getOneAndRemove(Map<String, List<KitePosAttrDTO>> map) {
        Map<String, Object> result = new HashMap<>();
        for (Entry<String, List<KitePosAttrDTO>> entry : map.entrySet()) {
            List<KitePosAttrDTO> attrs = entry.getValue();
            if (attrs != null) {
                result.put("key", entry.getKey());
                result.put("value", attrs);
                map.remove(entry.getKey());
                break;
            }
        }
        return result;
    }

    private void specialProcessForDiscountRateAttrValue(String sceneInstId) {
        List<KiteProdInstFunc> prodInstFuncs = querySceneInstService.listInsts(sceneInstId, Collections.singletonList(InstType.PROD_INST_FUNC));
        List<KiteProdInstFunc> disctProdInstFuncs = prodInstFuncs.stream()
            .filter(prodInstFunc -> KiteStringUtils.equalsAny(ProductCache.get(prodInstFunc.getSpecId()).getProdNbr(), "300000172", LocalKeyConsts.FUNC_PROD_ID_YF5GZF_ZK))
            .collect(Collectors.toList());
        disctProdInstFuncs.forEach(disctProdInstFunc -> {
            String discountRateOriginalValue = disctProdInstFunc.getAttrValue("discountRateOriginalValue");
            KiteAttr disctRateAttr = disctProdInstFunc.getAttr("200001694");
            if (Objects.nonNull(disctRateAttr) && KiteStringUtils.isNotEmpty(discountRateOriginalValue)) {
                disctRateAttr.setValue(discountRateOriginalValue);
                disctRateAttr.setValueDesc(discountRateOriginalValue);
                operateSceneInstService.setAttr(sceneInstId, disctProdInstFunc.getInstType(), disctProdInstFunc.getProdInstId(), disctRateAttr);
            }
        });
    }

    /**
     * 批量签订单个修改实例化
     * @param sceneInst
     * @param custId
     * @param staffId
     * @param posGoods
     * @param loginInfo
     */
    @Override
    public String initBatchSignOfferInst(KiteSceneInst sceneInst, String custId, String staffId, List<KitePosGoodsDTO> posGoods, LoginInfo loginInfo) {
        if (KiteListUtils.isEmpty(posGoods)) {
            return null;
        }
        posGoods = posGoods.stream()
            .filter(offerInst -> !GoodsInfoTransfer.isAddRoleOffer(offerInst.getCode(), offerInst.getCatagoryId()) && !GoodsHelper.isGift(offerInst.getCode()))
            .collect(Collectors.toList());
        if (KiteListUtils.isEmpty(posGoods)) {
            return null;
        }
        String provinceNbr = sceneInst.getProvinceNbr();
        KitePosGoodsDTO goods = posGoods.get(0);
        String offerId = goods.getCode();
        // 添加销售品实例
        String offerInstId = SpringUtil.getBean(LocalBatchAcceptBO.class).addOfferInst(sceneInst.getSceneInstId(),
            sceneInst, provinceNbr, custId, offerId);
        KiteOfferInst offerInst = this.querySceneInstService.getOfferInst(sceneInst.getCustId(), offerInstId);
        this.setExtOfferInstId(sceneInst.getSceneInstId(), goods, custId, offerInst);
        this.dealProducts(sceneInst.getSceneInstId(), custId, staffId, offerId, offerInstId, goods, false, loginInfo);
        return offerInstId;
    }
}
